如何检查联合是否包含类型(使用type_traits)?

时间:2018-06-28 15:45:37

标签: c++ c++11 c++14 unions

我有一个类似以下的功能模板:

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>允许检查联合,但是如何检查联合中的类型?

1 个答案:

答案 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

live example

使用:

raw_union<int, double> un;
un.emplace<int>(7);
std::cout << un.get_unsafe<int>() << "\n";

它不支持多个相同类型的联合成员。您要负责在使用.emplace<T>(x)之前调用T,并且要负责析构函数.dtor<T>()的使用。

访问未激活的成员就像使用原始C / C ++联合一样危险。