实际上,您介于岩石和坚硬的地方之间。
我会尝试一下boost::variant
,因为它附带的设施,否则重新创建类似的东西并不太难,但是它很长......
除了尺寸之外,您还需要注意对齐。在这里使用 C++11 会有所帮助,尽管可以在 C++03 中使用几个库/扩展来编写它。
请注意, aunion
并不是什么特别的东西,您可以轻松地以某种方式实现您自己的,并且喜欢boost::variant
将其“标记”。
几个助手会很好地提供帮助:
/// Size and Alignment utilties
constexpr size_t max(size_t t) { return t; }
template <typename... U>
constexpr size_t max(size_t l, size_t r, U... tail) {
return l > max(r, tail...) ? l : max(r, tail...);
}
template <typename... T>
struct size { static size_t const value = max(sizeof(T)...); };
template <typename... T>
struct alignment { static size_t const value = max(alignof(T)...); };
/// Position of a type in the list
template <typename...> struct position;
template <typename T>
struct position<T> {
static size_t const value = 0;
};
template <typename T, typename Head, typename... Tail>
struct position<T, Head, Tail...> {
static size_t const value =
std::is_same<T, Head>::value ? 0 : 1 + position<T, Tail...>::value;
};
/// Type at a given position
template <size_t, typename...> struct at;
template <size_t N, typename T, typename... Tail>
struct at<N, T, Tail...> { typedef typename at<N-1, Tail..>::type type; };
template <typename T, typename... Tail>
struct at<0, T, Tail...> { typedef T type; };
现在真正的乐趣开始了:如何以类型安全的方式应用一个函数,该函数的类型可能在运行时发生变化 :x ?
/// Function application
template <typename...> struct Apply;
template <typename H, typename... Tail>
struct Apply<H, Tail...> {
// Mutable
template <typename Func>
static void Do(Func& f, void* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
template <typename Func>
static void Do(Func const& f, void* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
// Const
template <typename Func>
static void Do(Func& f, void const* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H const*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
template <typename Func>
static void Do(Func const& f, void const* storage, size_t tag) {
if (tag == 0) { f(*reinterpret_cast<H const*>(storage)); }
else { Apply<Tail...>::Do(f, storage, tag-1); }
}
}; // struct Apply
/// We need recursion to end quietly even though `tag` is a runtime argument
/// we place the precondition that `tag` should be a valid index in the type
/// list so this should never be reached.
template <>
struct Apply<> {
template <typename... T>
static void Do(T...&&) { abort(); }
}; // struct Apply
现在我们可以使用它以类型安全的方式动态调度。
/// Variant itself
template <typename... List>
class Variant {
public:
/// Constructor & co
Variant() {
typedef typename at<0, List...>::type First;
new (&_storage) First();
}
Variant(Variant const& other) {
this->initialize(other);
}
Variant& operator=(Variant const& other) {
this->destroy();
this->initialize(other);
return *this;
}
~Variant() { this->destroy(); }
/// Conversions
template <typename T>
explicit Variant(T const& t) {
_tag = position<T, List...>::value;
new (&_storage) T(t);
}
template <typename T>
Variant& operator=(T const& t) {
_tag = position<T, List...>::value;
this->destroy();
new (&_storage) T(t);
return *this;
}
/// Applying a func
template <typename Func>
void apply(Func& f) { Apply<List...>::Do(f, &_storage, _tag); }
template <typename Func>
void apply(Func& f) const { Apply<List...>::Do(f, &_storage, _tag); }
template <typename Func>
void apply(Func const& f) { Apply<List...>::Do(f, &_storage, _tag); }
template <typename Func>
void apply(Func const& f) const { Apply<List...>::Do(f, &_storage, _tag); }
private:
void initialize(Variant const& v) {
struct {
template <typename T>
void operator()(T& t) const { new (_storage) T(t); }
void* _storage;
} copier = { &_storage };
v.apply(copier);
_tag = v._tag;
}
void destroy() {
struct {
template <typename T>
void operator()(T& t) const { t.~T(); }
} eraser;
this->apply(eraser);
}
std::aligned_storage<size<List...>::value,
alignment<List...>::value> _storage;
size_t _tag;
}; // class Variant
我说容易吗?
好吧,还有一个微妙的问题:operator=
实现不是异常安全的。在您的情况下,这应该不是问题,因为您在这些类型中没有动态内存分配。
参考: