40

これT v(x);直接初期化T v = x;呼ばれ、コピー初期化と呼ばれます。これは、コピー/移動されるT一時的なものを構築することを意味します(これはおそらく省略されます)。xv

リストの初期化では、標準はコンテキストに応じて2つの形式を区別します。直接リスト初期化と呼ばれ、T v{x};コピーリスト初期化と呼ばれます。T v = {x};

§8.5.4 [dcl.init.list] p1

[...]リストの初期化は、直接初期化またはコピー初期化のコンテキストで発生する可能性があります。直接初期化コンテキストでのリスト初期化は直接リスト初期化と呼ばれ、コピー初期化コンテキストでのリスト初期化はコピーリスト初期化と呼ばれます。[...]

ただし、標準全体でそれぞれ2つだけ参照があります。T{x}直接リスト初期化の場合、 ( )のような一時的なものを作成するときに言及され§5.2.3/3ます。copy-list-initializationの場合、return {x};§6.6.3/2)のようなreturnステートメントの式用です。

では、次のスニペットはどうですか?

#include <initializer_list>

struct X{
  X(X const&) = delete; // no copy
  X(X&&) = delete; // no move
  X(std::initializer_list<int>){} // only list-init from 'int's
};

int main(){
  X x = {42};
}

通常、パターンから、のmoveコンストラクターはdとして定義されているX x = expr;ため、コードのコンパイルに失敗すると予想されます。ただし、最新バージョンのClangとGCCは上記のコードを問題なくコンパイルし、少し掘り下げて(そして上記の引用を見つけて)、それは正しい動作のようです。この標準は、リストの初期化全体の動作を定義するだけであり、上記の点を除いて、2つの形式をまったく区別しません。まあ、とにかく、少なくとも私が見る限りでは。Xdelete

だから、私の質問をもう一度要約すると:

リストの初期化を(明らかに)まったく同じことを行う場合、2つの形式に分割することの使用は何ですか?

4

1 に答える 1

35

彼らはまったく同じことをしないからです。13.3.1.7 [over.match.list]で述べられているように:

copy-list-initializationで、明示的なコンストラクターが選択されている場合、初期化の形式が正しくありません。

つまり、コピーリスト初期化コンテキストでのみ暗黙的な変換を使用できます。

これは、均一な初期化を均一ではなく、均一にするために明示的に追加されました。ええ、私はそれがどれほど愚かに聞こえるか知っていますが、私に耐えてください。

2008年にN2640が公開され(PDF)、統一初期化の現状を見ていきます。T{...}特に、直接初期化( )とコピー初期化()の違いに注目しましたT = {...}

要約すると、懸念はexplicitコンストラクターが事実上無意味になるということでした。T整数から構築できるようにしたいタイプがあるが、暗黙的な変換は必要ない場合は、コンストラクターに明示的なラベルを付けます。

次に、誰かがこれを行います:

T func()
{
  return {1};
}

現在の文言がなければ、これは私のexplicitコンストラクターを呼び出します。explicitでは、コンストラクターがあまり変わらない場合、コンストラクターを作成することはどのようなメリットがありますか?

現在の表現では、少なくとも名前を直接使用する必要があります。

T func()
{
  return T{1};
}
于 2012-11-19T20:10:24.397 に答える