2014-01-07 5 views
9

У меня есть расхождение между поведением g ++ 4.8.1 и clang ++ 3.4.Инициализация статического члена класса constexpr типа enum-класса с помощью явной функции преобразования

У меня есть класс 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 

я вижу подобную картину при преобразовании в другой буквальный тип класса вместо перечислимого типа - г ++ отторгает инициализацию s1, лязг отвергает инициализация 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 

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


Edit: Несколько интересных вещей отметить:

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

отметить, что первые 3 примеры правильно компилировать на [Clang 3.5 SVN] (http://coliru.stacked-crooked.com/a/ dd5bbd2f90fe7457) – TemplateRex

+0

@TemplateRex интересно, спасибо – je4d

+0

также обратите внимание, что использование формы инициализации 'auto si = S (A {});' 'также работает для всех трех случаев: http://coliru.stacked-crooked.com/a/ 8f23cd452086ef40 Я не знаю, почему синтаксис 'S()' работает, когда 'S {}' не будет. – TemplateRex

ответ

3

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

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

Бьярне Страуструп говорит под errata for his book, что он зафиксирован в C++ 14

+0

На самом деле, я не уверен, что это применимо, поэтому я удалил свой предыдущий комментарий. Я думаю, что Бьярн ссылается на вопрос [1467] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1467), который применим только к агрегатам. Мой пример struct имеет пользовательский код c'tor по умолчанию и копирует c'tor, чтобы остановить его как совокупность. – je4d

+0

@ je4d: Я не уверен, что это не применимо. Мне кажется, что [decl.init] p14 говорит, что список инициализации в этом случае интерпретируется как создание временного, а затем преобразования типа. Если вы опустите слово «явным» из вашего кода, я думаю, что это сработает, что, по-видимому, указывает на то, что, хотя это сделано во время компиляции, семантика кажется, что это двухэтапный процесс. – Edward

+0

Какой документ вы используете? '[dcl.init] p14' из C++ 11 (N3290) здесь не применим. По моему чтению, [over.match.copy], точка 2, предложение 2 говорит, что здесь следует рассмотреть явные преобразования. – je4d

 Смежные вопросы

  • Нет связанных вопросов^_^