构造函数中的 C++14 constexpr 联合条件初始化
C++14 constexpr union conditional initialization in constructor
我想根据参数选择在构造函数中初始化的联合成员。以下是一个有效的示例:
struct A {
union {
int i;
float f;
};
A(double d, bool isint) {
if (isint) new(&i) int(d);
else new(&f) float(d);
}
};
当我使用 int
和 float
时,目标是使用其他更复杂的类型(但在 C++14 联合中仍然允许),因此使用放置-新的(而不是作业)。
问题是此构造函数不能 constexpr
,因为 constexpr
方法中不允许放置新的。有什么办法解决这个问题(除了使 isint
参数成为正式类型系统的一部分之外)?某种类型的条件初始化器列表可以工作,但我不知道有什么方法可以做到。
有个窍门。关键部分是:
- 联合的默认复制或移动构造函数复制对象表示(并因此复制活动成员),并且在常量表达式计算中是允许的。
- 您不能在初始化完成后更改常量表达式计算中的活动联合成员,但您可以委托给另一个构造函数来延迟选择。
- 如果委托给复制或移动构造函数,则可以传入另一个已初始化为正确状态的对象并复制其活动成员。
将这些放在一起,我们得到:
template<typename T> struct tag {};
struct A {
union {
int i;
float f;
};
constexpr A(tag<int>, double d) : i(d) {}
constexpr A(tag<float>, double d) : f(d) {}
constexpr A(double d, bool isint) : A(isint ? A(tag<int>(), d) : A(tag<float>(), d)) {}
};
constexpr A a(1.0, true); // ok, initializes 'i'
constexpr A b(5, false); // ok, initializes 'f'
这被最近的 Clang、GCC 和 EDG 所接受,并且只需要 C++11 constexpr
。
警告: GCC 5.1.0 存在错误编译上述代码的错误(将 a
和 b
初始化为 0
) ;此错误不存在于早期或更高版本的 GCC 中。
对于简单的可构造对象,不需要new
。您可以简单地通过赋值运算符开始对象生命周期和 select 活动 union
成员。
struct A {
union {
int i;
float f;
};
A(double d, bool isint) {
if (isint) i = d;
else f = d;
}
};
如果成员内部某处真的有一个构造函数,那么有必要使用理查德的答案。
我想根据参数选择在构造函数中初始化的联合成员。以下是一个有效的示例:
struct A {
union {
int i;
float f;
};
A(double d, bool isint) {
if (isint) new(&i) int(d);
else new(&f) float(d);
}
};
当我使用 int
和 float
时,目标是使用其他更复杂的类型(但在 C++14 联合中仍然允许),因此使用放置-新的(而不是作业)。
问题是此构造函数不能 constexpr
,因为 constexpr
方法中不允许放置新的。有什么办法解决这个问题(除了使 isint
参数成为正式类型系统的一部分之外)?某种类型的条件初始化器列表可以工作,但我不知道有什么方法可以做到。
有个窍门。关键部分是:
- 联合的默认复制或移动构造函数复制对象表示(并因此复制活动成员),并且在常量表达式计算中是允许的。
- 您不能在初始化完成后更改常量表达式计算中的活动联合成员,但您可以委托给另一个构造函数来延迟选择。
- 如果委托给复制或移动构造函数,则可以传入另一个已初始化为正确状态的对象并复制其活动成员。
将这些放在一起,我们得到:
template<typename T> struct tag {};
struct A {
union {
int i;
float f;
};
constexpr A(tag<int>, double d) : i(d) {}
constexpr A(tag<float>, double d) : f(d) {}
constexpr A(double d, bool isint) : A(isint ? A(tag<int>(), d) : A(tag<float>(), d)) {}
};
constexpr A a(1.0, true); // ok, initializes 'i'
constexpr A b(5, false); // ok, initializes 'f'
这被最近的 Clang、GCC 和 EDG 所接受,并且只需要 C++11 constexpr
。
警告: GCC 5.1.0 存在错误编译上述代码的错误(将 a
和 b
初始化为 0
) ;此错误不存在于早期或更高版本的 GCC 中。
对于简单的可构造对象,不需要new
。您可以简单地通过赋值运算符开始对象生命周期和 select 活动 union
成员。
struct A {
union {
int i;
float f;
};
A(double d, bool isint) {
if (isint) i = d;
else f = d;
}
};
如果成员内部某处真的有一个构造函数,那么有必要使用理查德的答案。