9

g++ 4.8.1 と clang++ 3.4 の動作に矛盾があります。

type への変換関数をA持つリテラル型の classがあります。explicit constexprenum class E

Gcc では、場合によっては変換関数を使用して型の定数式から型のconstexpr変数を初期化できますが、変数が静的クラス メンバーの場合はそうではありません (以下)。EAe2

Clang は、すべてのコンテキスト ( e1e2およびe3) で初期化を拒否します。

[over.match.conv]p1明示的な変換関数の使用によると、ここでは OK です

enum class E { e };
struct A { explicit constexpr operator const E() const noexcept { return E::e; } };

constexpr E e1{A{}};                      // Gcc: OK, Clang: Error
struct B { static constexpr E e2{A{}}; }; // Gcc: Error, Clang: Error
void f() { static constexpr E e3{A{}}; }  // Gcc: OK, Clang: Error

列挙型の代わりに別のリテラル クラス型に変換するときに、同様のパターンが見られます。g++ は の初期化をs1拒否し、clang は の初期化を拒否s1s2ますs3。に従って、これらも有効であるべきだと思います[over.match.copy]p1

struct S { constexpr S(){} constexpr S(const S&){}};
struct A { explicit constexpr operator S() const noexcept { return S(); } };

constexpr S s1{A{}};                      // Gcc: OK, Clang: Error
struct B { static constexpr S s2{A{}}; }; // Gcc: Error, Clang: Error
void f() { static constexpr S s3{A{}}; }  // Gcc: OK, Clang: Error

どちらかが正しい場合、どのコンパイラが正しいですか?


編集:注意すべき興味深い点がいくつかあります:

  1. 結果は、clang-3.4 と clang-svn の間で異なります。以下のコメントを参照してください。
  2. 初期化に括弧の代わりに括弧を使用する場合、e2/s2e1// e3/の間にはまだ違いがありs1ます。 http://coliru.stacked-crooked.com/a/daca396a63425c6bs3を参照してください。gcc と clang-svn は同意しますが、e2 と s2 を拒否することが正しいとは思えません。
4

1 に答える 1

3

奇妙なことに、Clang はこれらを拒否するのが正しいようです。

その理由は、C++11 標準にバグがあり、{}コピー コンストラクターが機能しないためです。()これが、コンストラクターが機能する理由ですが、{}コンストラクターは機能しません。

Bjarne Stroustrup は、彼の本の正誤表の下で、C++14 で修正されたと述べています。

于 2014-01-26T12:58:14.853 に答える