Программа с конструктором noexcept, принятая gcc, отклоняется clang

Код:

struct T { T() {} };

struct S
{
    T t;

    S() noexcept = default;
};

int main()
{
//    S s;
}

g++ 4.9.2 принимает это без каких-либо ошибок или предупреждений, однако, сообщения clang 3.6 и 3.7 для строки 7:

error: exception specification of explicitly defaulted default constructor does not match the calculated one

Однако, если строка S s; не закомментирована, g++ 4.9.2 теперь сообщает:

noex.cc: In function 'int main()':
noex.cc:12:7: error: use of deleted function 'S::S()'
     S s;
       ^
noex.cc:7:5: note: 'S::S() noexcept' is implicitly deleted because its  exception-specification does not match the implicit exception-specification ''
     S() noexcept = default;
     ^

Какой компилятор подходит для исходного кода?


Фон:

g++ даже позволяет добавить в main следующее:

std::cout << std::is_constructible<S>::value << '\n';

который выводит 0. Я столкнулся с этой проблемой при использовании clang для компиляции сложного кода, который сильно использовал шаблоны, SFINAE и noexcept. В этом коде S и T находятся шаблонные классы; поэтому поведение зависит от того, какие типы S были созданы. Clang отклоняет его с этой ошибкой для некоторых типов, тогда как g++ разрешает это, а SFINAE работает на основе is_constructible и подобных признаков.

Ответ 1

Зависит от версии стандарта, с которым вы консультируетесь.

N3337 [dcl.fct.def.default]/p2:

Явно-дефолтная функция [...] может иметь явный спецификация исключения только в том случае, если она совместима (15.4) с спецификацией исключения для неявного объявления.

который делает ваш исходный код плохо сформированным.

Это было изменено на CWG-выпуск 1778 для чтения (N4296 [dcl.fct.def.default]/p3):

Если функция, явно заданная по умолчанию, объявляется с помощью исключение-спецификация, которая несовместима (15.4) с спецификацией исключения по неявному объявлению, затем

  • если функция явно дефолтована по первому объявлению, она определяется как удаленная;
  • в противном случае программа плохо сформирована.

что означает, что теперь конструктор просто определяется как удаленный. (В приведенной выше формулировке были внесены изменения, сделанные в N4285, после публикации на С++ 14, в результате чего некоторые изменения очистки были чисто редакционными. Версия N3936 по существу является то же самое.)

Предположительно GCC реализует разрешение CWG1778, а Clang - нет.