如何使用两种类型的并集
How to use a union of two types
我正在尝试制作一个可以容纳string
和int
的vector
。
我已经尝试了下面的代码,但我得到了编译错误
错误:使用已删除的函数"my_union::~my_union()"
我做错了什么?
#include <iostream>
#include <vector>
using namespace std;
union my_union
{
string str;
int a;
};
int main()
{
vector<my_union> v;
my_union u; // error: use of deleted function 'my_union::~my_union()'
u.str = "foo";
v.push_back(u);
return 0;
}
从这里开始
如果并集包含一个具有非平凡特殊成员函数(默认构造函数、复制/移动构造函数、拷贝/移动赋值或析构函数)的非静态数据成员,则该函数在并集中默认会被删除,并且需要由程序员显式定义。
必须为并集显式定义析构函数,以替换为string
自动删除的析构函数。
还要注意,这仅在c++11中有效。在早期版本中,在联合中根本不能有具有非平凡特殊成员函数的类型。
从实际的角度来看,这可能仍然不是一个好主意。
当您使用一个基本上不是纯旧数据的类创建联合时,在C++11中,它允许您这样做。但它会隐式删除大多数特殊的成员函数,如析构函数。
union my_union
{
string str;
int a;
};
实际问题是,在破坏点,C++不知道联合的上述部分中的哪个是有效的。
您可以通过使用标记的并集来解决此问题,并跟踪活动的并集,在这种情况下手动进行销毁。
所以我们可以得到这样的东西:
struct tagged_union {
enum active {nothing, string, integer} which_active;
template<active...As>
using actives = std::integral_sequence<active, As...>
using my_actives = actives<nothing, string, integer>;
struct nothingness {};
union my_union
{
nothingness nothing;
std::string str;
int a;
~my_union() {};
} data;
using my_tuple = std::tuple<nothingness, std::string, int>;
template<active which>
using get_type = std::tuple_element_t<(std::size_t)which, my_tuple>;
template<class F>
void operate_on(F&& f) {
operate_on_internal(my_actives{}, std::forward<F>(f));
}
template<class T, class F>
decltype(auto) operate_on_by_type(F&& f) {
return std::forward<F>(f)(reinterpret_cast<T*>(&data));
}
// const versions go here
private:
// a small magic switch:
template<active...As, class F>
void operate_on_internal(actives<As...>, F&& f) {
using ptr = void(*)(my_union*,std::decay_t<F>*);
const ptr table[]={
[](my_union* self, std::decay_t<F>* pf){
std::forward<F>(*pf)(*(get_type<As>*)self);
}...,
nullptr
};
table[which](&data, std::address_of(f));
}
public:
template<class...Args>
tagged_union(Active w, Args&&...args) {
operate_on([&](auto& t){
using T = std::decay_t<decltype(t)>();
::new((void*)std::addressof(t)) T(std::forward<Args>(args)...);
which = w;
});
}
tagged_union():tagged_union(nothing){}
~tagged_union() {
operate_on([](auto& t){
using T = std::decay_t<decltype(t)>();
t->~T();
which=nothing;
::new((void*)std::addressof(t)) nothingness{}; // "leaks" but we don't care
});
}
};
它基本上是一个类似CCD_ 5的东西在C++11中如何工作的原始草图。
它涉及一些沉重的魔力。
以上内容尚未编译,但设计是合理的。然而,一些名义上的C++14编译器不喜欢围绕完整的lambda进行包扩展,这将需要更多的样板。
在C++11之前,不允许在联合中使用std::string
,如下所示:
联合不能包含具有非平凡的非静态数据成员特殊成员函数(复制构造函数、复制赋值运算符、,或析构函数)。
由于C++11,您可以在联合中使用std::string
,正如@Rotem已经回答的那样,您需要为字符串显式定义析构函数,或者显式调用析构函数
str.~basic_string<char>();
- 类型总是使用其大小存储在内存中吗
- 为什么在我的函数类型后使用引用运算符 (&) 允许我修改它返回的值?
- 使用 make 编译 MPI,几个命名空间错误,例如"错误:未知类型名称'使用'?
- 在模板化成员函数的返回类型中使用 std::enable_if 时的编译器差异
- Google Sparsehash 在类型上使用 realloc(),这很难复制
- 将 lower_bound/upper_bound 与 2 种不同的类型一起使用
- 根据动态选择类型C++模板使用情况
- 不允许将SDL_Cursor与unique_ptr:error不完整类型一起使用
- 为什么引用类型在使用临时对象访问时是左值
- 在枚举类型上使用std::max是不是一种糟糕的做法
- 将提升属性映射与捆绑类型一起使用
- 使用 std::future 的不完整类型无效使用
- 为什么在函数参数类型中使用模板参数包作为其模板参数列表无法显式指定
- 如何将模运算符与其他数据类型一起使用
- 澄清了双精度数据类型的使用
- 类型检测:使用variadic参数正确实现计算平均值的函数
- 如何使用%类型指令使用std ::变体类型
- C++ 在知道变量类型之前使用自动定义的变量
- 在任何类类型上使用模板方法中的 new
- 如何将STD :: Iterator与基本类型Uint8_t**使用