Инициализация статического члена класса constexpr типа enum-класса с помощью явной функции преобразования
У меня есть несоответствие между поведением g++ 4.8.1 и clang++ 3.4.
У меня есть класс A
буквального типа, который имеет explicit
constexpr
функция преобразования в тип enum class E
,
GCC позволяет мне инициализировать constexpr
переменные типа E
из константного выражения типа A
использование функции преобразования в некоторых случаях, но не тогда, когда переменная является статическим членом класса (e2
ниже)
Clang отклоняет инициализацию во всех контекстах (e1
, e2
а также e3
).
В соответствии с [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
Я вижу похожую модель при преобразовании в другой тип литерального класса вместо типа enum - 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
/s3
см. http://coliru.stacked-crooked.com/a/daca396a63425c6b. gcc и clang-svn согласны, но я не уверен, что отклонение e2 и s2 является правильным.
1 ответ
Как ни странно, Кланг, кажется, прав, отвергая их.
Причина в том, что в стандарте C++11 есть ошибка, из-за которой {}
не работает для конструкторов копирования. Вот почему ()
конструкторы работают, но {}
конструкторы нет.
Бьярн Страуструп говорит, что в книге написано, что она исправлена в C++14