9

I have a discrepancy between the behaviour of g++ 4.8.1 and clang++ 3.4.

I've got a class A, of literal type, that has an explicit constexpr conversion function to type enum class E.

Gcc allows me to initialize constexpr variables of type E from a constant expression of type A using the conversion function in some cases, but not when the variable is a static class member (e2 below)

Clang rejects the initialization in all contexts (e1, e2 and e3).

According to [over.match.conv]p1 use of an explicit conversion function is OK here

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

I see a similar pattern when converting to another literal class type instead of an enum type - g++ rejects the initialization of s1, clang rejects the initialization of s1, s2 and s3. I think these should be valid as well, as per [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

Which compiler, if either, is right?


Edit: A couple of interesting things to note:

  1. The results are different between clang-3.4 and clang-svn, see comments below.
  2. When using parens for the initialization instead of braces, there is still a difference between e2/s2 and e1/e3/s1/s3, see http://coliru.stacked-crooked.com/a/daca396a63425c6b. gcc and clang-svn agree, but I'm not convinced that rejecting e2 and s2 is correct.
4

1 回答 1

3

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

原因是 C++11 标准中有一个错误{}不适用于复制构造函数。这就是()构造函数起作用,而{}构造函数不起作用的原因。

Bjarne Stroustrup 在他的书的勘误表中说,它已在 C++14 中修复

于 2014-01-26T12:58:14.853 回答