web-dev-qa-db-ja.com

別の構造体から派生した構造体を中括弧で初期化できないのはなぜですか?

このコードを実行すると:

struct X {
    int a;
};

struct Y : public X {};

X x = {0};
Y Y = {0};

私は得る:

error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’

ブレースの初期化が基本クラスで機能するのに、派生クラスでは機能しないのはなぜですか?

38
Eric

あなたの問題は 集合体の初期化 に関係しています:struct Xは集合体ですが、struct Yはそうではありません。集計(8.5.1)に関する標準的な見積もりは次のとおりです。

集合体は、ユーザー提供のコンストラクター(12.1)、非静的データメンバー用のブレースまたはイコールイニシャライザー(9.2)、プライベートまたは保護された非静的データメンバー(条項11)、基本クラスなし(条項10)、および仮想関数(10.3)なし。

この句は、classに基本クラスがある場合、それが集合体ではないことを指定します。ここで、struct Ystruct Xを基本クラスとして持っているため、集約型にすることはできません。

あなたが抱えている特定の問題に関しては、標準から次の条項を取ります。

8.5.4で指定されているように、アグリゲートがイニシャライザリストによって初期化されると、イニシャライザリストの要素は、添え字またはメンバーの昇順で、アグリゲートのメンバーのイニシャライザとして使用されます。各メンバーは、対応する初期化子句からコピー初期化されます。初期化句が式であり、式を変換するために絞り込み変換(8.5.4)が必要な場合、プログラムの形式が正しくありません。

X x = {0}を実行すると、集約初期化を使用してa0に初期化します。ただし、Y y = {0}を実行すると、struct Yは集計型ではないため、コンパイラーは適切なコンストラクターを探します。暗黙的に生成されたコンストラクター(デフォルト、コピー、および移動)はいずれも、単一の整数では何も実行できないため、コンパイラーはコードを拒否します。


このコンストラクタールックアップに関して、clang ++からのエラーメッセージは、コンパイラーが実際に何をしようとしているのかについてもう少し明確です( オンライン例 ):

Y Y = {0};
  ^   ~~~

main.cpp:5:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Y &' for 1st argument

struct Y : public X {};
       ^

main.cpp:5:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'Y &&' for 1st argument

struct Y : public X {};
       ^

main.cpp:5:8: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided

使用例をサポートするために集計初期化を拡張する 提案およびがあることに注意してくださいC++ 17にそれを作りました。私がそれを正しく読んだ場合、それはあなたの例をあなたが期待するセマンティクスで有効にします。つまり... C++ 17準拠のコンパイラを待つだけです。

48
Morwenn