C++14 がファイナライズされた直後にCore issue 1467の解決によって対処されたケースに遭遇しました。
foo
まず、classは集合体であることに注意してください。あなたのコードはの直接リスト初期化を行っていfoo
ます。リスト初期化のルールは [8.5.4p3] にあります。
C++14 (公開された標準に最も近い作業草案である N4140 から引用) では、上記の段落は次のように始まります。
型のオブジェクトまたは参照のリスト初期化は、T
次のように定義されます。
- が集合体の場合
T
、集合体の初期化が実行されます (8.5.1)。
[...]
そのため、クラスが集約の場合、コンパイラは集約の初期化を試みますが、失敗します。
これは問題として認識され、ワーキング ドラフトで修正されました。現在のバージョン N4527 から引用すると、上記の段落は次のように始まります。
型のオブジェクトまたは参照のリスト初期化は、T
次のように定義されます。
T
がクラス型であり、イニシャライザ リストに型cv の要素が 1 つある場合U
(ここで、U
はT
または から派生したクラスT
)、オブジェクトはその要素から初期化されます (コピー リスト初期化の場合はコピー初期化、または直接初期化による場合)。直接リスト初期化)。
- それ以外の場合、
T
が文字配列であり、初期化子リストに適切に型指定された文字列リテラル (8.5.2) である単一の要素がある場合、そのセクションで説明されているように初期化が実行されます。
- それ以外の場合、
T
が集合体の場合、集合体の初期化が実行されます (8.5.1)。
[...]
あなたの例は、最初の箇条書きで説明されているケースに該当し、デフォルトのコピーコンストラクターを使用して直接リスト初期化されます(直接初期化であるため、それが であるかどうかに関係foo
なく)explicit
。
つまり、コンパイラが欠陥レポートで解決策を実装する場合です。
- GCC 5.2.0 (および 6.0.0 トランク) はそうしているようですが、それに関連するバグがあるようです
explicit
。
- Clang 3.6.0 はそうではありませんが、3.8.0 トランクはそうであり、正しく実行します (問題で
explicit
はありません)。
- MSVC 14 にはありますが、IDE の IntelliSense にはありません (下の波線
bar
- IntelliSense で使用される EDG コンパイラも更新されていないようです)。
更新: この回答が書かれて以来、作業草案は、質問の例と上記の説明に関連するいくつかの方法でさらに修正されました。
- CWG 2137は、上で引用した段落の最初の箇条書きが、その例外をすべてのクラス タイプに適用することで少し行き過ぎたことを示しています (問題のメモには関連する例が含まれています)。箇条書きの冒頭は次のようになります。
- 論文P0398R0に含まれるCWG 1518の決議は、コンストラクターを宣言するクラス(たとえデフォルトであっても) が集合体ではなくなったことを示しています。
explicit
explicit
これは、すべての変更が実装された後、質問の例が;の有無にかかわらず機能することを意図しているという事実を変更しません。それを機能させる基本的なメカニズムがわずかに変更されたことを知っておく価値があります。
これらの変更はすべて不具合レポートの解決策であるため、コンパイラが C++14 および C++11 モードの場合にも適用されるはずです。