Этот вопрос мотивирован этот.
Рассмотрим следующий код:
struct B {};
struct S {
B b; // #1
S() = default;
template <typename ...dummy> // #2
constexpr S(const S&) {}
template <typename ...dummy> // #3
constexpr S(S &other)
: S(const_cast<const S&>(other)) // #4
{}
};
S s;
constexpr S f() {return s;}
int main() {
constexpr auto x = f();
}
GCC успешно компилирует этот код, но Clang отклоняет его (Пример на Godbolt.org). Сообщение об ошибке, выдаваемое Clang:
<source>:21:20: error: constexpr variable 'x' must be initialized by a constant expression
constexpr auto x = f();
^ ~~~
<source>:13:11: note: read of non-constexpr variable 's' is not allowed in a constant expression
: S(const_cast<const S&>(other))
^
<source>:13:11: note: in call to 'S(s)'
<source>:18:25: note: in call to 'S(s)'
constexpr S f() {return s;}
^
<source>:21:24: note: in call to 'f()'
constexpr auto x = f();
^
<source>:17:3: note: declared here
S s;
^
Обратите внимание: если мы удалим любой из # 2, # 3 или # 4, оба компилятора примут этот код. Если мы заменим # 1 на int b = 0;
, оба компилятора отклонят его.
У меня вопрос:
- Какой компилятор правильный в соответствии с действующим стандартом?
- Если GCC верен, почему замена # 1 на
int b = 0;
делает этот код некорректным? Если Clang верен, почему удаление любого из пунктов №2, №3 или №4 делает этот код правильным?