Как проверить, содержит ли union тип (используя type_traits)? - PullRequest
0 голосов
/ 28 июня 2018

У меня есть шаблон функции, подобный следующему:

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 голосов
/ 28 июня 2018

Вы не можете.

Boost :: Вариант и STD :: Вариант решения этой проблемы, так что объединение несет в себе информацию о типе вам нужно.

Вы можете создать необработанный союз следующим образом:

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 ++.

...