Программа с конструктором 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 - нет.