10

C++11 より前では、 A a = 1;which と多かれ少なかれ同等のようなものを書くことで、コピーの初期化を行うことができましたA a = A(1);。つまり、最初にテンポラリが作成され、次にコピー ctor が呼び出されます。コピーの省略に関係なく、これは概念的にそうでなければならず、コピー ctor にアクセスできる必要があります。

C++11 のリストの初期化では、 と書くことでコピー リストの初期化を行うことができますA a = {1, 2};。私の意見では、これは とほぼ同等であるはずA a = A(1, 2);です。ただし、GCC と clang では、A a = {1, 2}(private として宣言することにより) コピーおよび移動 ctor にアクセスできない場合でもコンパイルします。それでも、A a = 1;対応するコピー/移動 ctor にアクセスできない場合、GCC または clang でコンパイルされません。したがって、直接リストの初期化とA a = {1, 2};ほぼ同等のようです。A a{1, 2};これと実際のダイレクト リストの初期化との違いは、A a = {1, 2};2 つの int を取る ctor が明示的である場合はコンパイルされないことです。この点では、A a = {1, 2};コピーの初期化に似ています。

だから、私の質問は次のとおりA a = {1, 2};です。概念的には、表現の正確なセマンティクスは何ですか? 概念的には、コピー省略は邪魔になりません。

4

1 に答える 1

11

標準はそれをかなりよく説明しています。[dcl.init.list]/3:

型のオブジェクトまたは参照のリスト初期化は、T次のように定義されます。

  • [...]
  • それ以外の場合、Tがクラス型の場合、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され、オーバーロード解決 (13.3、13.3.1.7) によって最適なコンストラクターが選択されます。引数のいずれかを変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。

[over.match.list] (強調鉱山):

非集約型クラス タイプのオブジェクトTがリスト初期化されている場合 (8.5.4)、オーバーロードの解決では、次の 2 つのフェーズでコンストラクターが選択されます。

  • 最初は、候補関数はクラスの初期化子リスト コンストラクター (8.5.4) でTあり、引数リストは単一の引数としての初期化子リストで構成されます。

  • 実行可能な初期化子リスト コンストラクターが見つからない場合、オーバーロードの解決が再度実行されます。この場合、候補関数はクラスのすべてのコンストラクターでTあり、引数リストは初期化子リストの要素で構成されます。

初期化子リストに要素がなく、T に既定のコンストラクターがある場合、最初のフェーズは省略されます。
copy-list-initialization では、explicitコンストラクターが選択されている場合、初期化の形式が正しくありません。

したがって、(あなたの場合のように) 初期化子リスト コンストラクターが見つからない場合、初期化子リストの要素がコンストラクター呼び出しの引数を構成します。
実際、direct-list-initialization と copy-list-initializationの唯一の違いは、最後の太字の文で説明されています。

これは、リストの初期化の利点の 1 つです。いずれにせよ使用されない特別なメンバー関数が存在する必要はありません。

于 2014-11-17T01:47:12.157 に答える