将联合转换为其成员类型之一

时间:2018-01-11 19:10:18

标签: c++ c++11 casting unions

我坚持使用一些生成的C代码,这有点乱。我目前正在将它包装到C ++ 11界面中,以免发生疯狂。

C代码包含已标记的联合。我希望能够提供一种简单的方法来阅读它们,例如:

template <typename U, typename T>
T readTaggedUnion(const U & un) {
    return static_cast<T>(un);
}

这合法吗?

我也希望能够对此进行健全性检查,但看起来type_traits在工会方面做得不多。并且联盟的所有标签都有自己生成的类型,因此无法以通用方式读取这些标签。

我已阅读continue,但它对我没有帮助。

编辑:我的代码是根据一些输入文件生成的,这些文件可以更改,我无法控制这些文件。我只知道输出结构如何,所以我知道哪些部分总是相同的,哪些部分取决于输入文件。

为名为TestChoice的结构生成的代码示例,其中包含4个不同的内容:

/* Dependencies */
typedef enum TestChoice_PR {
    TestChoice_PR_NOTHING,  /* No components present */
    TestChoice_PR_integer,
    TestChoice_PR_optional,
    TestChoice_PR_enm,
    TestChoice_PR_setof
} TestChoice_PR;

/* TestChoice */
typedef struct TestChoice {
    TestChoice_PR present;
    union TestChoice_u {
        INTEGER_t    integer;
        TestOptional_t   optional;
        TestEnumType_t   enm;
        TestSetOf_t  setof;
    } choice;

    /* Context for parsing across buffer boundaries */
    asn_struct_ctx_t _asn_ctx; // This is not relevant
} TestChoice_t;

1 个答案:

答案 0 :(得分:1)

我很想回复boost::variant<Ts...>(或者你可以升级到C ++ 17,std::variant)。

无论如何

// quick test to ensure we aren't casting from a non-union:
template<class U>
void union_test( U const volatile& ) {
  static_assert( std::is_union< U >::value, "only unions allowed as an argument" );
}
template<class T, class U>
T union_cast( U const& u ) {
  union_test(u);
  using pT = typename std::remove_reference<T>::type;
  return std::forward<T>(*(pT const*)std::addressof(u));
}
template<class T, class U>
T union_cast( U const&& u ) {
  union_test(u);
  using pT = typename std::remove_reference<T>::type;
  return std::forward<T>(*(pT const*)std::addressof(u));
}
template<class T, class U>
T union_cast( U&& u ) {
  union_test(u);
  using pT = typename std::remove_reference<T>::type;
  return std::forward<T>(*(pT*)std::addressof(u));
}

使用:

struct pt {
  int x,y;
};
union x {
  int a;
  double d;
  pt p;
};

void foo( int type, x in ) {
  switch(type) {
    case 0:
      std::cout << union_cast<int>(in) << "\n";
      return;
    case 1:
      std::cout << union_cast<double>(in) << "\n";
      return;
    case 2:
      std::cout << union_cast<pt>(in).x << "," << union_cast<pt>(in).y << "\n";
      return;
  }
}