g++ 4.8.1 と clang++ 3.4 の動作に矛盾があります。
type への変換関数をA
持つリテラル型の classがあります。explicit
constexpr
enum class E
Gcc では、場合によっては変換関数を使用して型の定数式から型のconstexpr
変数を初期化できますが、変数が静的クラス メンバーの場合はそうではありません (以下)。E
A
e2
Clang は、すべてのコンテキスト ( e1
、e2
および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 は の初期化を拒否s1
しs2
ます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
どちらかが正しい場合、どのコンパイラが正しいですか?
編集:注意すべき興味深い点がいくつかあります:
- 結果は、clang-3.4 と clang-svn の間で異なります。以下のコメントを参照してください。
- 初期化に括弧の代わりに括弧を使用する場合、
e2
/s2
とe1
//e3
/の間にはまだ違いがありs1
ます。 http://coliru.stacked-crooked.com/a/daca396a63425c6bs3
を参照してください。gcc と clang-svn は同意しますが、e2 と s2 を拒否することが正しいとは思えません。