在constexpr中使用简单的复制/移动分配联合时发生冲突

时间:2015-12-01 08:49:06

标签: c++ c++11 clang c++14 constexpr

考虑以下代码

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.

LIVE EXAMPLE

以上所有内容均适用于clang 3.7.0版本,但较新版本clang 3.8.0 (trunk 253951)没有说明constexpr S & operator = (S const &) = default;(它允许编译此类代码),但后果是相同的。

对于普通的复制/移动构造函数,但是用户提供的赋值运算符类似的代码(构造)编译得很好。

我认为问题(bug)在用户声明的特殊功能中,但它应该是合法的。

另请注意this code的最后和最后一个条款。相当精心设计(在我看来)variantconstexpr中变得无用,因为编译器对下一个定义的解释不同:

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并且不重要。它肯定是错误的,因为没有人告诉你这个。

0 个答案:

没有答案