Я только что наткнулся на следующие различия между GCC и Clang, касающиеся явно заданного по умолчанию constexpr ctor и некоторого наследования...
template <typename T>
struct A {
constexpr A() = default;
T v;
};
struct B : A<int> {
constexpr B() = default;
};
GCC немедленно отклоняет код, в то время как Clang позволяет создавать версии без constexpr обоих типов. Я предполагаю, что Clang, вероятно, прав, но я не уверен на 100%...





Проблема сводится к: это конструктор constexpr, который инициализирует по умолчанию некоторый нестатический член данных встроенного типа допустим, если не используется?
тл;др:
Для конструктора без шаблона нет, недопустимо оставлять любые нестатические элементы данных неинициализированными.
Для конструктора шаблонов да, допустимо иметь некоторые (но не все, диагностика не требуется) инстанцированные специализации шаблонов для которых созданный конструктор не соответствует требованиям конструктора constexpr.
В этом случае GCC прав, а Clang нет.
GCC выдает следующее сообщение об ошибке, которое очень информативно:
prog.cc:8:13: error: explicitly defaulted function 'constexpr B::B()' cannot be declared as 'constexpr' because the implicit declaration is not 'constexpr':
8 | constexpr B() = default;
| ^
prog.cc:3:13: note: defaulted constructor calls non-'constexpr' 'A<T>::A() [with T = int]'
3 | constexpr A() = default;
| ^
prog.cc:3:13: note: 'A<T>::A() [with T = int]' is not usable as a 'constexpr' function because:
prog.cc:4:5: note: defaulted default constructor does not initialize 'int A<int>::v'
4 | T v;
| ^
Обратите внимание, что ошибка возникает в конструкторе B,
вместо A,
чей конструктор просто «непригоден для использования в качестве функции constexpr
потому что [] конструктор по умолчанию по умолчанию
не инициализирует int A<int>::v."
Согласно [dcl.constexpr]/4:
The definition of a constexpr constructor shall satisfy the following requirements:
- the class shall not have any virtual base classes;
- each of the parameter types shall be a literal type.
In addition, either its function-body shall be
= delete, or it shall satisfy the following requirements:
- [...]
- every non-variant non-static data member and base class subobject shall be initialized ([class.base.init]);
- [...]
Здесь v имеет тип int и не инициализирован.
Поэтому кажется, что конструктор A
не может быть объявлен constexpr.
Однако [dcl.конструктор]/6 говорит:
If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is still a constexpr function or constexpr constructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for a constexpr function or constexpr constructor when considered as a non-template function or constructor, the template is ill-formed, no diagnostic required.
Следовательно, конструктор A, объявленный constexpr
на самом деле действителен,
даже при создании экземпляра для T = int!
Проблема в конструкторе B.
B — обычный класс (в отличие от шаблона класса),
и чтобы его конструктор был (просто) объявленconstexpr,
A<int> должен иметь constexpr конструктор,
это не так.
Поэтому этот код следует отвергнуть, как это делает GCC.
(Обратите внимание, что оба компилятора отвергают инициализацию такого типа, Например:
A a{};
B b{};
Приведенный выше код отвергается обоими компиляторами.)
Как упоминалось в комментарий,
инициализируйте A::v и GCC (и стандарт) будут счастливы.
инициализируйте
A::vи gcc будет счастлив.