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

Ori*_*ent 5 c++ clang constexpr c++11 c++14

考虑以下代码

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());
Run Code Online (Sandbox Code Playgroud)

我发现存在矛盾.

我想使用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.
Run Code Online (Sandbox Code Playgroud)

但版本#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.
Run Code Online (Sandbox Code Playgroud)

现场例子

以上所有版本都是版本的clang 3.7.0,但clang 3.8.0 (trunk 253951)没有更新版本说明constexpr S & operator = (S const &) = default;(它允许编译这样的代码),但结果是相同的.

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

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

另请查看此代码的最后一个但最后一个条款.由于下一个定义的编译器的解释不同,相当精心设计(在我看来)variant变得毫无用处constexpr:

struct S {};
Run Code Online (Sandbox Code Playgroud)

和:

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;
};
Run Code Online (Sandbox Code Playgroud)

但两者在我的脑海中是相同的(第二个被编译器认为不是POD,但谁在乎?).

为什么缺省的默认赋值运算符struct不是constexpr

更新:

删除析构函数的声明会使问题消失.因此,即使用户声明的(非用户提供的)析构函数也使隐式定义的默认赋值运算符不被标记constexpr为非平凡的.这肯定是错误的,因为没有人告诉这件事.