Given the following code
struct S { constexpr S() = default; constexpr S(S const &) = default; constexpr S(S &) = default; constexpr S(S &&) = default; #if 1 S & operator = (S const &) = default; S & operator = (S &) = default; S & operator = (S &&) = default; #else constexpr S & operator = (S const &) = default; constexpr S & operator = (S &) = default; constexpr S & operator = (S &&) = default; #endif ~S() = default; }; struct U { union { S s; }; constexpr U() : s{} { ; } }; inline constexpr bool test() { U v; U w; v = w; return true; } static_assert(test());
I found that there is a contradiction.
I want to use union (or euqally union-like class) in constexpr .
Version #if 1 gives an error ( error: constexpr function never produces a constant expression ):
main.cpp:31:23: error: constexpr function never produces a constant expression [-Winvalid-constexpr] inline constexpr bool test() ^ main.cpp:35:7: note: non-constexpr function 'operator=' cannot be used in a constant expression v = w; ^ main.cpp:19:8: note: declared here struct U ^ main.cpp:39:15: error: static_assert expression is not an integral constant expression static_assert(test()); ^~~~~~ main.cpp:35:7: note: non-constexpr function 'operator=' cannot be used in a constant expression v = w; ^ main.cpp:39:15: note: in call to 'test()' static_assert(test()); ^ main.cpp:19:8: note: declared here struct U ^ 2 errors generated.
But version #if 0 also gives an error ( error: defaulted definition of copy assignment operator is not constexpr ):
main.cpp:12:5: error: defaulted definition of copy assignment operator is not constexpr constexpr S & operator = (S const &) = default; ^ main.cpp:13:5: error: defaulted definition of copy assignment operator is not constexpr constexpr S & operator = (S &) = default; ^ main.cpp:14:5: error: defaulted definition of move assignment operator is not constexpr constexpr S & operator = (S &&) = default; ^ main.cpp:35:7: error: object of type 'U' cannot be assigned because its copy assignment operator is implicitly deleted v = w; ^ main.cpp:24:11: note: copy assignment operator of 'U' is implicitly deleted because field 's' has no copy assignment operator S s; ^ 4 errors generated.
LIVE EXAMPLE
Everything is higher for clang 3.7.0 version clang 3.7.0 , but the newer version of clang 3.8.0 (trunk 253951) does not say anything about constexpr S & operator = (S const &) = default; (it allows you to compile such code), but the consequences are the same.
For trivial copy / move constructor, but user-provided assignment operators are exactly the same as code (build).
I think the problem (error) in the user-declared special functions, but it should be legal in general.
Also pay attention to the last and last, but one section of this code . A fairly well-designed (in my opinion) variant becomes useless in constexpr due to differences in the compiler's interpretation of the following definitions:
struct S {};
and
struct S { constexpr S() = default; constexpr S(S const &) = default; constexpr S(S &) = default; constexpr S(S &&) = default; S & operator = (S const &) = default; S & operator = (S &) = default; S & operator = (S &&) = default; ~S() = default; };
But both are equivalent in my mind (the second is recognized by the compiler, not POD, but who needs it?).
Why is the default empty assignment operator struct not constexpr ?
UPDATE:
Removing the destructor declaration causes the problem to disappear. Thus, even a user-declared (not user-provided) destructor makes implicitly defined assignment operators not marked as constexpr and be nontrivial. This is definitely a mistake, because no source talks about it.