This question is motivated by this one.
Consider the following code:
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 compiles this code successfully, but Clang rejects it (Example on Godbolt.org). The error message produced by Clang is
<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;
^
Note if we remove any of #2, #3 or #4, both compilers accept this code. If we replace #1 with int b = 0;
, both compilers reject it.
My question is:
- Which compiler is correct according to the current standard?
- If GCC is correct, why does replacing #1 with
int b = 0;
make this code ill-formed? If Clang is correct, why does removing any of #2, #3 or #4 make this code well-formed?