好吧,标准仍然说支持初始化一个联合只初始化第一个成员。我想这会把这个问题更多地放在“如果......不是很好吗?”类别。
是否必须这样?毕竟,我们现在有其他类型的自动类型检测。
auto x = 3; // int
auto s = "foo"; // char *
auto w = L"Foo"; // wchar_t *
那为什么不与工会合作?给出:
struct init
{
int t;
union {
long long x;
char *s;
wchar_t *w;
};
};
目前,您只能支持初始化init::x
(使用int
),而不是s
或w
。
可以扩展自动类型检测,以便根据初始化程序的类型选择初始化的联合成员:
auto init initial_data [] = {
{ 0, 3 }, // initializes x, brace elision
{ 1, "foo" }, // initializes s
{ 2, L"Foo" } // initializes w
};
(当然,这不应该在当前标准中编译。)
这样就可以将所有initial_data
放在一个初始化列表中。 (我怀疑auto关键字必须去其他地方)。
是否有什么东西使这个坏主意(除了“没人想到它”或“它太难实现”)?目前你必须做一些可怕的事情,如:
#define RI(X) reinterpret_cast<long long>(X)
const init initial_data[] = {
{ 0, 3 }, // initializes x, brace elision
{ 1, RI("foo") }, // initializes s
{ 2, RI(L"Foo") } // initializes w
};
我不想经历这些扭曲,除了std::exception
必须用std::string
初始化(即基于char
),所以我不能只是包含所有wchar_t*
的初始化列表。我真的很喜欢所有这些初始化器在同一个地方。
答案 0 :(得分:3)
在我的介绍中我提到过:
(虽然联合可以有成员函数(包括构造函数和析构函数)
我刚刚意识到这可以让你自己编写所需的构造函数!
struct init {
init(long long v) : t(type::longlong), x(v) {}
init(char const* v) : t(type::pcsz), s(v) {}
init(wchar_t const* v) : t(type::pwcsz), w(v) {}
enum class type { longlong, pcsz, pwcsz } t;
union { long long x; char const* s; wchar_t const* w; };
};
现在编译:
init initial_data [] = {
3 , // initializes x, brace elision
"foo" , // initializes s
L"Foo" // initializes w
};
Q值。有什么东西让这个坏主意(除了“没人想到它”或“它太难实现”)
一般来说,union
通常是一个坏主意。很难安全地使用它们。在这方面,他们在C ++中有点“二等”公民(虽然一个联盟可以有成员函数(包括构造函数和析构函数),但现在不是虚函数)。
让编译器选择“the”槽来接收初始化器很可能很快就会遇到歧义。
使用大括号初始化,他们可以添加一些限制(没有缩小/扩大转换),就像C ++ 11中的初始化列表一样。
但这都是幻想。缺点是: 这不是语言功能 。
boost::variant
有此行为。
注释
which()
成员基本上是您的类型判别器(t
)BOOST_VARIANT_MINIMIZE_SIZE
const*
!<强> Live On Coliru 强>
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/variant.hpp>
using init = boost::variant<long long, char const*, wchar_t const*>;
#include <iostream>
int main() {
init initial_data [] = {
3 , // initializes x, brace elision
"foo" , // initializes s
L"Foo" // initializes w
};
for(auto& v : initial_data)
std::cout << v.which() << "\t" << v << "\n";
}
输出:
0 3
1 foo
2 0x401f14