考虑以下代码
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());
我发现存在矛盾。
我想在union
中使用constexpr
(或类似于类似联合的类)。
版本#if 1
会出错(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.
但版本#if 0
也会出错(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.
以上所有内容均适用于clang 3.7.0
版本,但较新版本clang 3.8.0 (trunk 253951)
没有说明constexpr S & operator = (S const &) = default;
(它允许编译此类代码),但后果是相同的。
对于普通的复制/移动构造函数,但是用户提供的赋值运算符类似的代码(构造)编译得很好。
我认为问题(bug)在用户声明的特殊功能中,但它应该是合法的。
另请注意this code的最后和最后一个条款。相当精心设计(在我看来)variant
在constexpr
中变得无用,因为编译器对下一个定义的解释不同:
struct S {};
和
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;
};
但两者在我的脑海中是相同的(第二个被编译器认为不是POD,但谁在乎?)。
为什么默认值为空struct
的赋值运算符不是constexpr
?
删除析构函数声明会使问题消失。因此,即使是用户声明的(非用户提供的)析构函数,也不会将隐式定义的默认赋值运算符标记为constexpr
并且不重要。它肯定是错误的,因为没有人告诉你这个。