Инициализация статического члена класса constexpr типа enum-класса с помощью явной функции преобразования

У меня есть несоответствие между поведением g++ 4.8.1 и clang++ 3.4.

У меня есть класс Aбуквального типа, который имеет explicitconstexpr функция преобразования в тип 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

Какой компилятор, если любой, правильный?


Изменить: пара интересных вещей для заметки:

  1. Результаты отличаются между clang-3.4 и clang-svn, см. Комментарии ниже.
  2. Когда для инициализации используются скобки вместо скобок, разница между e2/s2 а также e1/e3/s1/s3см. http://coliru.stacked-crooked.com/a/daca396a63425c6b. gcc и clang-svn согласны, но я не уверен, что отклонение e2 и s2 является правильным.

1 ответ

Как ни странно, Кланг, кажется, прав, отвергая их.

Причина в том, что в стандарте C++11 есть ошибка, из-за которой {} не работает для конструкторов копирования. Вот почему () конструкторы работают, но {} конструкторы нет.

Бьярн Страуструп говорит, что в книге написано, что она исправлена ​​в C++14

Другие вопросы по тегам