@RR
2017-03-22T03:55:30.000000Z
字数 1467
阅读 139
flex-c++
union SimpleUnion {int i;bool b;std::string s;};SimpleUnion u;
the default constructor of "SimpleUnion" cannot be referenced -- it is a deleted function Args
上面这段代码会有一个编译错误。原因在于std::string是一个class对象,它有自己的构造和析构函数,不允许直接这么用在union里面。考虑下面这样的代码, C++的编译器在构造SimpleUnion u;的时候,没法预知union里面需要的是一个std::string,而调用其构造函数。
SimpleUnion u;u.s.size();
只有is trivially default constructible的对象才能这样简单的放在union里面。比如一个类包含一个非默认的构造函数;包含虚函数之类的,那么它就不是trivially default constructible。比如说下面的C和C2结构体都不满足条件。
struct C{void virtual fun(){}};struct C2 {C2(){}};static_assert(std::is_trivially_default_constructible<C2>::value,"C is not trivial default constructible");
对应的在static_assert这里都会有编译错误。这里的std::is_trivially_default_constructible是一个C++的标准模板,可以用来批判一个对象是不是trivially default constructible
既然编译器无法自动构造union对象,那么给union加上构造函数就可以了。比如下面的代码不会有编译错误。
union SimpleUnion {SimpleUnion() : s("") {}~SimpleUnion() {}int i;bool b;std::string s;};SimpleUnion u;
但是这仅仅是没有编译错误了,但是实际上还是有很多问题。比如说std::string s的析构函数怎么被调用?在SimpleUnion的析构函数里面,我们无法判断当前union里面是一个int还是个std::string。所以说,一般来说你只能放一个对象的指针在union里面。而在union之外来管理指针的生存周期。
std::variant 是一个类型安全的union,是在C++14里面添加的新特性,但是暂时在主流的C++编译器里面并没有支持。所以我使用了boost库里面的variant,他们是类似的。
int main(int argc, char** argv){using Variant = boost::variant<int, std::string>;Variant v;v = 1;v = "string";std::string s = boost::get<std::string>(v);return 0;}
variant,tuple, vector概念上的区别。