11

C++11

このプログラムは、 のvectornamedmyVecを初期化しint vector、ループを使用して各 innervectorの要素を出力します。しかし、追加の中括弧を使用するとどうなるかを確認しようとすると、予期しない結果が得られました。以下もこの LiveWorkSpaceにあり、コンパイラを簡単に切り替えることができます。g++ 4.8.0までしかコンパイルできませんmyVec[5]clang++ 3.2すべてをコンパイルします:

#include <iostream>
#include <vector>

int main()
{
    std::vector<std::vector<int>> myVec =
    {
        /* myVec[0] */ {1, 2},
        /* myVec[1] */ {},
        /* myVec[2] */ {{}},
        /* myVec[3] */ { {}, {} },
        /* myVec[4] */ { {}, {}, {} },
        /* myVec[5] */ {{{}}}

        /* myVec[6] */  // , { {{}}, {{}} }       // g++ 4.8.0 COMPILER ERROR
        /* myVec[7] */  // , {{{{}}}}             // g++ 4.8.0 COMPILER ERROR
        /* myVec[8] */  // , { {{{}}}, {{{}}} }   // g++ 4.8.0 COMPILER ERROR
    };

    // loop for printing
    for (unsigned int i = 0; i < myVec.size(); ++i)
    {
        std::cout << "myVec[" << i << "]: ";
        for (unsigned int j = 0; j < myVec.at(i).size(); ++j)
        {
            std::cout << myVec.at(i).at(j) << ", ";
        }
        std::cout << std::endl;
    }
    return 0;
}

実際のg++ 4.8.0出力:

myVec[0]: 1, 2,
myVec[1]:
myVec[2]: 0,
myVec[3]: 0, 0,
myVec[4]: 0, 0, 0,
myVec[5]: 0,

分析:

myVec[0]: {1, 2}:

期待どおりの出力が得られました。

myVec[1]: {}:

期待どおりの出力が得られました。

myVec[2]: {{}}:

これは のベクトルですint 0。内側のブレースは to を初期化int0ます。

myVec[3]: { {}, {} }:

2 つの内側の中括弧は、inteach を に初期化し0ます。

myVec[4]: { {}, {}, {} }:

3 つの内側の中かっこは、inteach を に初期化し0ます。

myVec[5]: {{{}}}:

myVec[2]中括弧をさらに追加して、コンパイラ エラーが発生する前に中括弧をどこまで追加できるかを確認したかったのです。これがコンパイルされる理由と、その要素が として出力される理由がわかりません0

たとえば、 にint j = {}初期化jされ0ます。vector<vector<int>> v = { {{}} }最も内側{}をに初期化しint 0、 と同等にしvector<vector<int>> v = { {0} }ます。では、それは何でvector<vector<int>> u = { {{{}}} }、なぜコンパイルされるのでしょうか?

仮説myVec[6]: { {{}}, {{}} }:

上記と同じパターンに従って、2 組の二重中括弧を含むベクターを作成したいと考えました。しかし、これはコンパイルされません。なぜこれが複数のゼロを与えるパターンを破るのか理解できません。

仮説myVec[7]: {{{{}}}}:

myVec[5]中括弧をさらに追加して、コンパイラ エラーが発生する前に中括弧をどこまで追加できるかを確認したかったのです。これがパターンを壊してコンパイルしない理由がわかりません。

仮説myVec[8]: { {{{}}}, {{{}}} }:

myVec[7]2 組の三重ブレースを使用してベクトルを作成するように拡張したかったのです。これがコンパイルされない理由もわかりません。

までのすべてがmyVec[5]コンパイルされた場合、残りはなぜコンパイルされないのですか?

4

1 に答える 1

4

このコードをコンパイルしてみてください。それはあなたの問題を説明するはずです:

int i = {};   // initializes i to int()
int j = {{}}; // fails to compile

コードで受け入れられる理由{{{}}}は、ctor の処理方法に関連する gcc バグ (明確にする必要がある) のようです:

struct foo {
    foo( std::initializer_list<int> ) {}
};
void f()
{
   foo bar1( {{{}}} ); // compiles fine
   foo bar2 = {{{}}}; // compiles fine
}

編集 (Johannes Schaub に感謝) - コピー ctor を削除すると、最初のバリアントがコンパイルできなくなります。

struct foo {
    foo( std::initializer_list<int> ) {}
    foo( const foo& ) = delete;
};
void f()
{
   foo bar1( {{{}}} ); // fails to compile: use of deleted function ‘foo::foo(const foo&)’
   foo bar2 = {{{}}}; // still compiles, neither deleting move ctor, nor assignment operator does not affect that, is copy ctor of std::initializer_list involved?
}

メンバー関数の場合、失敗します:

struct foo {
    void moo( std::initializer_list<int> ) {}
};
void f()
{
   foo bar;
   bar.moo( {{{}}} ); // fails to compile
}

このコードも失敗します:

std::initializer_list<int> l = {{{}}}; // fails to compile

std::vector の同じ状況 ctor とメンバー関数:

void f()
{
    std::vector<int> v( {{{}}} ) // compiles fine;
    v.assign( {{{}}} ); // fails to compile
};

gcc バージョン 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)

于 2013-03-03T05:25:12.627 に答える