The basic usage of the variant in boost:
Copy Code code as follows:
typedef VARIANT<INT,CHAR, double> VT;
VT v = 1;
v = ' 2 ';
v = 12.32;
The advantage of a variant is that the type can be erased, and the values of different types are unified into a variant, although this variant can only hold the defined type, but it is sufficient in many cases. When the value is taken, the real value is obtained by get<t> (v). However, when the T type does not match the type of V, a Bad_cast exception is thrown. Boost's variant often throws no more information, and does not know exactly what type of conversion failed, which is inconvenient when abnormal debugging occurs. Therefore, consider using c++11 to implement a vairiant, a variant that can easily know what type conversion failed when the value was taken.
Create a Variant to solve the problem:
First, you define a char buffer internally.
A buffer is used to hold a Variant value that is a value of a type in several types defined by a variant, so the buffer is large enough to hold the value of the type maximum (sizeof), and the size of the buffer must be computed at compile time. So the first thing you need to fix is the problem of the buffer definition that the variant value holds.
Second, to solve the problem of assignment.
When assigning a value to Vairiant, the type ID of the value needs to be recorded so that the value is followed by the type. When you save a value to an internal buffer, you also need to create an object in the buffer with palcement new. Also, the problem is that when assigning a value, you need to check whether the defined type in the variant contains that type, and if not, compile without it to ensure that the assignment is valid.
Third, to solve the problem of value-taking.
Through the type of value, to determine whether the type match, if not match, the details will be printed out to facilitate debugging.
Key technologies to create variants:
1. Find the Biggest typesize
The problem to be solved in the first question is how to find the size of the type with the largest size in multiple types. See how to find the maximum type size from a variety of types.
Copy Code code as follows:
Template<typename T, TypeName ... Args>
struct Maxtype:std::integral_constant<int,
(sizeof (t) >maxtype<args...>::value sizeof (t): Maxtype<args...>::value) >
{};
Template<typename t>
struct maxtype<t>: std::integral_constant<int, sizeof (T) >{};
With this maxtype, you can get the largest maxsize of the type at compile time: Maxtype<types...>::value.
2. Type checking and creating objects in buffer
In the second question, two questions need to be addressed, 1. Check that the type of assignment is in the defined type; 2. Create objects and destructors in buffers;
Take a look at how to determine whether a type list contains a type:
Copy Code code as follows:
Template < typename T, TypeName ... List >
struct Contains:std::true_type {};
Template < TypeName T, TypeName Head, TypeName ... Rest >
struct contains<t, head, rest...>
: std::conditional< std::is_same<t, Head>::value, Std::true_type,
Contains<t, rest...>>::type{};
Template < typename T >
struct contains<t>: std::false_type{};
By contains<t the value of bool, Types>::vaule can determine whether or not a certain type is included.
and see how to create an object in the buffer.
Creates an object on the buffer by placement new, new (data) T (value), where data represents a char buffer, and T represents a type. objects created on the buffer must also be ~t through the vairiant, so a help class for the destructor is also required:
Copy Code code as follows:
Template<typename ... Args>
struct Varianthelper;
Template<typename T, TypeName ... Args>
struct Varianthelper<t, args...> {
inline static void Destroy (Type_index id, void * data)
{
if (id = = Type_index (typeid (T))
((t*) (data))->~t ();
Else
Varianthelper<args...>::D Estroy (ID, data);
}
};
template<> struct Varianthelper<> {
inline static void Destroy (Type_index id, void * data) {}
};
by Varianthelper::D Estroy function, you can deconstruct a variant.
3. Value-taking problem
The third problem is to resolve the value problem, and if an exception occurs, print out the details. This is relatively simple, look at the following implementation code on the line.
How the complete variant of the C++11 is implemented:
Copy Code code as follows:
#include <typeindex>
#include <iostream>
#include <type_traits>
using namespace Std;
Template<typename T, TypeName ... Args>
struct Maxtype:std::integral_constant<int,
(sizeof (t) >maxtype<args...>::value sizeof (t): Maxtype<args...>::value) >
{};
Template<typename t>
struct maxtype<t>: std::integral_constant<int, sizeof (T) >{};
Template < typename T, TypeName ... List >
struct Contains:std::true_type {};
Template < TypeName T, TypeName Head, TypeName ... Rest >
struct contains<t, head, rest...>
: std::conditional< std::is_same<t, Head>::value, Std::true_type, Contains<t,
rest...>>::type{};
Template < typename T >
struct contains<t>: std::false_type{};
Template<typename ... Args>
struct Varianthelper;
Template<typename T, TypeName ... Args>
struct Varianthelper<t, args...> {
inline static void Destroy (Type_index id, void * data)
{
if (id = = Type_index (typeid (T))
((t*) (data))->~t ();
Else
Varianthelper<args...>::D Estroy (ID, data);
}
};
template<> struct Varianthelper<> {
inline static void Destroy (Type_index id, void * data) {}
};
Template<typename ... Types>
Class Variant
{
typedef varianthelper<types...> helper_t;
Public
Variant (void): M_typeindex (typeID (void))
{
}
~variant ()
{
helper_t::D Estroy (M_typeindex, &m_data);
}
Template<typename t>
BOOL Is ()
{
return (M_typeindex = = Type_index (typeid (T)));
}
Template<typename t>
t& get ()
{
if (! Is<t> ())
{
cout << typeid (T). Name () << "is not defined." << "The current type is" <<
M_typeindex.name () << Endl;
Throw Std::bad_cast ();
}
return * (t*) (&m_data);
}
Template <class T,
class = TypeName Std::enable_if<contains<typename
Std::remove_reference<t>::type, types...>::value>::type>
Variant (t&& value): M_typeindex (Type_index (typeID (T)))
{
helper_t::D Estroy (M_typeindex, &m_data);
typedef typename STD::REMOVE_REFERENCE<T>::TYPE U;
New (M_data) U (std::forward<t> (value));
}
Private
Char m_data[maxtype<types...>::value];
Std::type_index M_typeindex;
};
Test code:
Copy Code code as follows:
void Testvariant ()
{
typedef variant<int, Char, double> CV;
int x = 10;
CV v =x;
v = 1;
v = 1.123;
v = "";//compile error
V.get<int> (); 1
V.get<double> (); 1.23
V.get<short> (); Exception:short is not defined. The current type is
Int.
V.is<int> ();//true
}
Summary: The C++11 implementation variant is consistent with boost.variant in usage, but is simpler to implement and 50 lines of code to handle. But also can be thrown when the exception of the detailed information, easy to debug.
C++11 Boost Technology Exchange Group: 296561497, welcome everyone to exchange technology.