【发布时间】:2015-11-26 10:32:36
【问题描述】:
与constexpr 和union 一起玩我发现,我无法更改constexpr 中union 的活动成员。只有一个例外:union 的空类。
constexpr bool t()
{
struct A {};
struct B {};
union U { A a; B b; } u{};
u.a = A{};
u.b = B{};
return true;
}
static_assert(t());
constexpr bool f()
{
struct A { char c; };
struct B { char c; };
union U { A a; B b; } u{};
u.a = A{};
u.b = B{}; // error originating from here
return true;
}
static_assert(f());
第一个函数可能会产生常量表达式。但是第二个不行。硬错误说:
main.cpp:23:15: error: static_assert expression is not an integral constant expression
static_assert(f());
^~~
main.cpp:20:11: note: assignment to member 'b' of union with active member 'a' is not allowed in a constant expression
u.b = B{};
^
main.cpp:20:9: note: in call to '&u.b->operator=(B{})'
u.b = B{};
^
main.cpp:23:15: note: in call to 'f()'
static_assert(f());
^
1 error generated.
1.) 是否可以在常量表达式中更改union 的活动成员?
我试图破坏活动成员,但这是不允许的,因为一般来说,析构函数不是constexpr。我还尝试使用放置operator new(::new (&u.b) B{2};),但也未使用。 reinterpret_cast 也不允许在常量表达式中使用。也禁止改变共同初始子序列的成员。
2.) 有没有办法使可变的(在改变活动替代类型的意义上)字面 boost::variant-like 类型?如果可能的话,它的存储方式如何?
3.) 在运行时对union 的非活动成员进行分配是否是未定义的行为?使用放置operator new 来构造union 的普通可复制类型的非活动成员以避免在运行时 初步破坏活动成员是否是未定义的行为?
附加:
我可以更改整个文字类型union,但不能更改它的非活动成员:
constexpr
bool
f()
{
struct A { char c; };
struct B { char c; };
union U
{
A a; B b;
constexpr U(A _a) : a(_a) { ; }
constexpr U(B _b) : b(_b) { ; }
};
U a(A{});
a.a = A{}; // check active member is A
U b(B{});
b.b = B{}; // check active member is B
a = b;
a = B{}; // active member is B!
return true;
}
static_assert(f());
因此对于普通可复制类型的文字类型variant,转换赋值运算符将是template< typename T > constexpr variant & operator = (T && x) { return *this = variant(std::forward< T >(x)); }。
【问题讨论】:
-
你的编译标志是什么?我couldn't reproduce it on Coliru.
-
@n.m.我用clang 3.7.0
-
标准的这个区域相当混乱。 P0137R0 的一些修订应该希望能稍微清理一下。
标签: c++ c++14 unions constexpr variant