📄 variant.h
字号:
typedef char RawBuffer_t[sizeof(T)];
enum ObjectState_e { eNone, ePreConstruct, ePostConstruct };
T &obj_;
ObjectState_e eObjState_;
RawBuffer_t bufferOrg_;
RawBuffer_t bufferNew_;
private:
void SetObj(const RawBuffer_t &buf) throw()
{
memcpy(&reinterpret_cast<char &>(obj_), buf, sizeof(buf));
}
void GetObj(RawBuffer_t &buf) throw()
{
memcpy(buf, &reinterpret_cast<const char &>(obj_), sizeof(buf));
}
public:
explicit RawDataKeeper(T &obj)
: obj_(obj), eObjState_(eNone)
{}
// add const U & version ?
template<typename U>
void ConstructNew(U &src)
{
assert(eObjState_ == eNone);
GetObj(bufferOrg_);
eObjState_ = ePreConstruct;
new (&obj_) T(src);
eObjState_ = ePostConstruct;
GetObj(bufferNew_);
SetObj(bufferOrg_);
}
void SetNew() throw()
{
assert(eObjState_ == ePostConstruct);
obj_.~T();
SetObj(bufferNew_);
eObjState_ = eNone;
}
~RawDataKeeper()
{
switch(eObjState_)
{
case ePostConstruct:
SetObj(bufferNew_);
obj_.~T();
// fall
case ePreConstruct:
SetObj(bufferOrg_);
// fall
case eNone:
break;
}
}
private:
RawDataKeeper(const RawDataKeeper &);
RawDataKeeper& operator=(const RawDataKeeper &);
};
//
// based on Eric Fridman's safe_swap from boost Variant
//
// strong exception-safety guarantee.
//
// !WARNING!
// SafeSwap CANNOT be safely used in the general case if either
// argument's data members may be accessed concurrently.
//
template<typename T>
void SafeSwap(T &lhs, T &rhs)
{
typedef RawDataKeeper<T> RhsDataKeeper;
typedef RawDataKeeper<T> LhsDataKeeper;
RhsDataKeeper rhsKeeper(rhs);
rhsKeeper.ConstructNew(lhs);
LhsDataKeeper lhsKeeper(lhs);
lhsKeeper.ConstructNew(rhs);
rhsKeeper.SetNew();
lhsKeeper.SetNew();
}
//
// based on Eric Fridman's safe_assign from boost Variant
//
// strong exception-safety guarantee.
//
// !WARNING!
// SafeAssign CANNOT be safely used in the general case if either
// argument's data members may be accessed concurrently.
//
template<typename T, typename U>
void SafeAssign(T &lhs, const U &src)
{
typedef RawDataKeeper<T> LhsDataKeeper;
LhsDataKeeper lhsKeeper(lhs);
lhsKeeper.ConstructNew(src);
lhsKeeper.SetNew();
}
template<typename T>
inline void SwapHelper(T &lhs, T &rhs)
{
using namespace std;
swap(lhs, rhs);
}
} // namespace Private
////////////////////////////////////////////////////////////////////////////////
// class template Variant
// Implements a discriminated union in C++
////////////////////////////////////////////////////////////////////////////////
template <class TList, class AlignedPODType = AlignedPOD<TList> >
class Variant
{
// VC7: fatal error C1067: compiler limit :
// debug information module size exceeded
// Therfore define this type here
typedef typename AlignedPODType::Result Align;
public:
typedef TList Types;
// Default constructor
// Initializes the Variant with a default-constructed object of the
// first type in the typelist
Variant()
{
typedef typename TList::Head T;
new(&buffer_[0]) T;
vptr_ = VTableImpl<T>::GetVPTR();
}
// Copy constructor
Variant(const Variant& rhs)
{
(rhs.vptr_->clone_)(rhs, *this);
}
private:
// Converting constructor; accepts any type in the typelist
// @@@ Suggested simple improvement: accept any type convertible to one of
// the types in the typelist. Use Loki::Conversion as a building block
template <class T>
void VariantConstruct(const T& val, double)
{
STATIC_CHECK((::Loki::TL::IndexOf<TList, T>::value >= 0),
Invalid_Type_Used_As_Initializer);
new(&buffer_[0]) T(val);
vptr_ = VTableImpl<T>::GetVPTR();
}
// Inter-Variant conversion constructor
// Current policy is: conversion succeeds iff the actual type of the source
// is one of the types accepted by the target
// @@@ Possible change: accept if the actual type of the source is
// convertible to one of the types accepted by the target. Problem to
// solve: handle ambiguities in a satisfactory manner. Suggestion: when
// in doubt, do closest to what the compiler would do.
template <class TList2, typename Align2>
void VariantConstruct(const Variant<TList2, Align2>& rhs, int)
{
typename Converter<Variant<TList2, Align2>, Variant>::Visitor v(*this);
typename Variant<TList2, Align2>::ConstStrictVisitor& visitor = v;
rhs.Accept(visitor);
}
public:
// VC7 don't support partial ordering
// The constructor initialization section
// is empty which make it to use function instead
// without the int = 0 the explicit seems to confuse
// VC7 when the copy constructor should be selected
// Crazy stuff
template <class T>
explicit Variant(const T& val, int = 0)
{
VariantConstruct(val, int(0));
}
// Canonic assignment operator
Variant& operator=(const Variant& rhs)
{
Private::SafeAssign(*this, rhs);
return *this;
}
private:
// Assignment operator from one of the allowed types
// This is necessary because the constructor is explicit
template <class T>
void VariantAssign(const T& rhs, double)
{
Private::SafeAssign(*this, rhs);
}
// Assignment from another Variant instantiation
template <class TList2, typename Align2>
void VariantAssign(const Variant<TList2, Align2>& rhs, int)
{
Private::SafeAssign(*this, rhs);
}
public:
// VC7 don't support partial ordering
template <class T>
Variant& operator=(const T& rhs)
{
// Both VariantAssign are the same in this implementation
VariantAssign(rhs, int(0));
return *this;
}
// ~
~Variant()
{
(vptr_->destroy_)(*this);
}
// Visitors definitions
// @@@ Possible improvement: add defintions of visitor who return
// something else than void
typedef ::Loki::Visitor<TList, void> StrictVisitor;
typedef ::Loki::Visitor<typename MakeConst<TList>::Result, void>
ConstStrictVisitor;
typedef ::Loki::NonStrictVisitor<TList, void> NonStrictVisitor;
typedef ::Loki::NonStrictVisitor<typename MakeConst<TList>::Result, void>
ConstNonStrictVisitor;
private:
// VTable structure
// The essential component of the fake vtable idiom, VTable contains
// pointers to functions, pointers that will be filled up with addresses
// of functions in VTableImpl
struct VTable
{
const std::type_info& (*typeId_)();
void (*destroy_)(const Variant&);
void (*clone_)(const Variant&, Variant&);
void (*swap_)(void* lhs, void* rhs);
void (*accept_)(Variant&, StrictVisitor&);
void (*acceptConst_)(const Variant&, ConstStrictVisitor&);
};
// VTable concrete implementations
// VTableImpl<T> contains definitions for all of a VTable's pointer to
// functions.
// VC7 thinks that Variant inside VTableImpl is template
typedef Variant VariantType;
template <class T>
struct VTableImpl
{
private:
static const std::type_info& TypeId()
{
return typeid(T);
}
static void Destroy(const VariantType& var)
{
const T& data = *reinterpret_cast<const T*>(&var.buffer_[0]);
(void)data.~T();
}
static void Swap(void* lhs, void* rhs)
{
Private::SwapHelper(*static_cast<T*>(lhs), *static_cast<T*>(rhs));
}
static void Clone(const VariantType& src, VariantType& dest)
{
new(&dest.buffer_[0]) T(
*reinterpret_cast<const T*>(&src.buffer_[0]));
dest.vptr_ = src.vptr_;
}
static void Accept(VariantType& var, StrictVisitor& visitor)
{
typedef typename StrictVisitor::ReturnType RType;
::Loki::Visitor<T,RType> &v = visitor;
v.Visit(*reinterpret_cast<T*>(&var.buffer_[0]));
}
static void AcceptConst(const VariantType& var, ConstStrictVisitor& visitor)
{
typedef typename ConstStrictVisitor::ReturnType RType;
::Loki::Visitor<const T,RType> &v = visitor;
v.Visit(*reinterpret_cast<const T*>(&var.buffer_[0]));
}
public:
static const VTable *GetVPTR()
{
static const VTable vTbl_ =
{
&TypeId,
&Destroy,
&Clone,
&Swap,
&Accept,
&AcceptConst,
};
return &vTbl_;
}
};
template <class T> friend struct VTableImpl;
private: // should be private; some compilers prefer 'public' :o}
enum { neededSize = MaxSize<TList>::result };
VTable const * vptr_;
union
{
Align dummy_;
char buffer_[neededSize];
};
public:
void swap(Variant& rhs)
{
if (this->TypeId() == rhs.TypeId())
{
(vptr_->swap_)(this->buffer_, rhs.buffer_);
}
else
{
Private::SafeSwap(*this, rhs);
}
}
const std::type_info& TypeId() const
{
return (vptr_->typeId_)();
}
template <typename T> T* GetPtr()
{
return TypeId() == typeid(T)
? reinterpret_cast<T*>(&buffer_[0])
: 0;
}
template <typename T> const T* GetPtr() const
{
return TypeId() == typeid(T)
? reinterpret_cast<const T*>(&buffer_[0])
: 0;
}
template <typename T> T& Get()
{
T* p = GetPtr<T>();
if (!p) throw std::runtime_error("Variant::Get() Invalid variant type");
return *p;
}
template <typename T> const T& Get() const
{
const T* p = GetPtr<T>();
if (!p) throw std::runtime_error("Variant::Get() const Invalid variant type");
return *p;
}
// Visitation primitives
// Although there are four visitor types, only two Accept functions are
// necessary, because the non-strict visitors inherit the strict visitors
void Accept(StrictVisitor& visitor)
{
(vptr_->accept_)(*this, visitor);
}
void Accept(ConstStrictVisitor& visitor) const
{
(vptr_->acceptConst_)(*this, visitor);
}
// Extracts the value of a Variant converted to a specific type
template <class To> To ConvertTo() const
{
typename ConverterTo<Variant, To>::Visitor v;
ConstStrictVisitor& visitor = v;
this->Accept(visitor);
return v.GetDestination();
}
// Changes the type of a Variant in-place
template <class To> void ChangeType()
{
Variant(this->ConvertTo<To>()).swap(*this);
}
};
////////////////////////////////////////////////////////////////////////////////
// Change log:
// July 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466)
////////////////////////////////////////////////////////////////////////////////
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -