我有一个类似以下的功能模板:
template<class U, class T>
T* unsafeCast(U* theUnion) {
reinterpret_cast<T*>(theUnion);
}
如果T是在联合U中包含的类型,那么如何确保仅编译该代码,以便以下内容成立?
union FooUnion {
int a;
double b;
} foo;
unsafeCast<FooUnion, int>(&foo); // compiles
unsafeCast<FooUnion, double>(&foo); // compiles
unsafeCast<FooUnion, char>(&foo); // does not compile
我了解到is_union
中的<type_traits>
允许检查联合,但是如何检查联合中的类型?
答案 0 :(得分:1)
你不能。
boost :: variant和std :: variant是此问题的解决方案,以便联合会附带您需要的类型信息。
您可以这样创建一个原始联合:
template<class T>
struct data_holder {
T data;
};
template<class...Ts>
struct union_data;
template<>
struct union_data<>{};
template<class T0>
struct union_data<T0>:data_holder<T0> {};
template<class T0, class...Ts>
struct union_data<T0, Ts...> {
union {
union_data<T0> lhs;
union_data<Ts...> rhs;
};
};
template<class...Ts>
struct raw_union:union_data<Ts...>{
template<class T>
constexpr static bool valid_type() {
return (std::is_same<T, Ts>{}||...); // rewrite in C++14/11
}
template<class T>
union_data<T>* get_data_ptr() {
static_assert( valid_type<T>() );
return reinterpret_cast<union_data<T>*>(this);
}
template<class T>
union_data<T> const* get_data_ptr() const{
static_assert( valid_type<T>() );
return reinterpret_cast<union_data<T> const*>(this);
}
template<class T>
T& get_unsafe() {
return get_data_ptr<T>()->data;
}
template<class T>
T const& get_unsafe() const {
return get_data_ptr<T>()->data;
}
template<class T, class...Us>
T& emplace( Us&&... us ) {
auto* ptr = ::new( (void*)get_data_ptr<T>() ) union_data<T>{ T(std::forward<Us>(us)...) };
return ptr->data;
}
template<class T>
void dtor() {
get_data_ptr<T>()->~T();
}
};
这是不安全且不受歧视的,但是会检查foo.get_unsafe<int>()
是否实际上包含int
。
使用:
raw_union<int, double> un;
un.emplace<int>(7);
std::cout << un.get_unsafe<int>() << "\n";
它不支持多个相同类型的联合成员。您要负责在使用.emplace<T>(x)
之前调用T
,并且要负责析构函数.dtor<T>()
的使用。
访问未激活的成员就像使用原始C / C ++联合一样危险。