通过显式转换函数初始化枚举类类型的静态constexpr类成员

je4*_*e4d 9 c++ constexpr c++11 enum-class

我在g ++ 4.8.1和clang ++ 3.4的行为之间存在差异.

我有一个A文字类型的类,它有一个explicit constexpr转换函数可以输入enum class E.

Gcc允许我在某些情况下使用转换函数从constexpr类型E的常量表达式初始化类型A的变量,但不是在变量是静态类成员时(e2下面)

Clang拒绝所有上下文(e1,e2e3)中的初始化.

根据[over.match.conv]p1使用显式转换功能可以在这里

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
Run Code Online (Sandbox Code Playgroud)

转换到另一个文字类型而不是枚举类型时,我看到一个类似的模式 - g ++拒绝初始化s1,clang拒绝初始化s1,s2s3.我认为这些也应该是有效的[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
Run Code Online (Sandbox Code Playgroud)

哪个编译器(如果有的话)是对的?


编辑:有几件有趣的事情需要注意:

  1. clang-3.4和clang-svn的结果不同,请参阅下面的评论.
  2. 当使用parens进行初始化而不是使用大括号时,e2/ s2e1/ e3/ s1/ 之间仍然存在差异s3,请参阅http://coliru.stacked-crooked.com/a/daca396a63425c6b.gcc和clang-svn同意,但我不相信拒绝e2和s2是正确的.

Edw*_*ard 3

奇怪的是,Clang 拒绝这些似乎是正确的。

原因是 C++11 标准中存在一个错误,该错误{}不适用于复制构造函数。这就是为什么()构造函数可以工作,但{}构造函数却不能。

Bjarne Stroustrup 在他的书勘误表中表示,该问题已在 C++14 中修复