I have tried for hours to code a class deriving from boost::variant
. But I do not understand what is the problem (I do not understand what the compilation error means).
What are the rules to implement a clean boost::variant
derived-class?
#include <boost/variant.hpp>
class MyVariant : public boost::variant<char,bool>
{
public:
MyVariant () : boost::variant<char,bool>( ) {}
template <typename T>
MyVariant( T& v) : boost::variant<char,bool>(v) {}
template <typename T>
MyVariant(const T& v) : boost::variant<char,bool>(v) {}
};
int main ()
{
MyVariant a;
MyVariant b = a; //compilation error
// MyVariant c = MyVariant();
// MyVariant d (true);
// MyVariant e ('E');
}
Why do I want to use inheritance? (EDIT to give more details to @zaufi)
const char*
as string
int
as long
enum
typesFor instance, in pseudo C++ code, my hopes:
class MyVariant : public boost::variant<char,bool,long,std::string>
{
typedef boost::variant<char,bool,long,std::string> super;
public:
// I know here I should specialize templeted constructors
// but I is more clear like that, isn't it?
MyVariant() : super('e') {} //empty -> char
MyVariant(char c) : super(std::string(1,c)){} //char -> string
MyVariant(const char* s) : super(std::string(s) ) {} //char* -> string
MyVariant(int v) : super(long (v) ) {} //TODO boundaries
/* other constructors ... */
enum Type
{
NONE, //my empty state = char type
BOOL,
LONG,
STRING
};
Type type() const { return (Type) which(); }
};
The basic snippet code (on top of the question) has been tested on different platforms
Below my errors for the two versions of GCC (I can remove one of the both if it bothers someone...)
$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ myVariant.cpp
/usr/include/boost/variant/variant.hpp: In constructor 'boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant(T&) [with T = MyVariant, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]':
myVariant.cpp:10: instantiated from 'MyVariant::MyVariant(T&) [with T = MyVariant]'
myVariant.cpp:19: instantiated from here
/usr/include/boost/variant/variant.hpp:1348: error: call of overloaded 'convert_construct(MyVariant&, long int)' is ambiguous
/usr/include/boost/variant/variant.hpp:1262: note: candidates are: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(T&, int, mpl_::false_) [with T = MyVariant, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]
/usr/include/boost/variant/variant.hpp:1321: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char, U1 = bool, U2 = boost::detail::variant::void_, U3 = boost::detail::variant::void_, U4 = boost::detail::variant::void_, U5 = boost::detail::variant::void_, U6 = boost::detail::variant::void_, U7 = boost::detail::variant::void_, U8 = boost::detail::variant::void_, U9 = boost::detail::variant::void_, U10 = boost::detail::variant::void_, U11 = boost::detail::variant::void_, U12 = boost::detail::variant::void_, U13 = boost::detail::variant::void_, U14 = boost::detail::variant::void_, U15 = boost::detail::variant::void_, U16 = boost::detail::variant::void_, U17 = boost::detail::variant::void_, U18 = boost::detail::variant::void_, U19 = boost::detail::variant::void_, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]
/usr/include/boost/variant/variant.hpp:1330: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(const boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char, U1 = bool, U2 = boost::detail::variant::void_, U3 = boost::detail::variant::void_, U4 = boost::detail::variant::void_, U5 = boost::detail::variant::void_, U6 = boost::detail::variant::void_, U7 = boost::detail::variant::void_, U8 = boost::detail::variant::void_, U9 = boost::detail::variant::void_, U10 = boost::detail::variant::void_, U11 = boost::detail::variant::void_, U12 = boost::detail::variant::void_, U13 = boost::detail::variant::void_, U14 = boost::detail::variant::void_, U15 = boost::detail::variant::void_, U16 = boost::detail::variant::void_, U17 = boost::detail::variant::void_, U18 = boost::detail::variant::void_, U19 = boost::detail::variant::void_, T0_ = char, T1 = bool, T2 = boost::detail::variant::void_, T3 = boost::detail::variant::void_, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_]
$ g++ --version
g++.exe (GCC) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ myVariant.cpp -I /c/.../include/
In file included from c:/.../include/boost/variant.hpp:17:0,
from myVariant.cpp:1:
c:/.../include/boost/variant/variant.hpp: In instantiation of 'boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::variant(T&) [with T = MyVariant; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]':
myVariant.cpp:9:66: required from 'MyVariant::MyVariant(T&) [with T = MyVariant]'
myVariant.cpp:18:25: required from here
c:/.../include/boost/variant/variant.hpp:1406:9: error: call of overloaded convert_construct(MyVariant&, long int)' is ambiguous
c:/.../include/boost/variant/variant.hpp:1406:9: note: candidates are:
c:/.../include/boost/variant/variant.hpp:1316:10: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(T&, int, mpl_::false_) [with T = MyVariant; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_; mpl_::false_ = mpl_::bool_<false>]
c:/.../include/boost/variant/variant.hpp:1376:10: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char; U1 = bool; U2 = boost::detail::variant::void_; U3 = boost::detail::variant::void_; U4 = boost::detail::variant::void_; U5 = boost::detail::variant::void_; U6 = boost::detail::variant::void_; U7 = boost::detail::variant::void_; U8 = boost::detail::variant::void_; U9 = boost::detail::variant::void_; U10 = boost::detail::variant::void_; U11 = boost::detail::variant::void_; U12 = boost::detail::variant::void_; U13 = boost::detail::variant::void_; U14 = boost::detail::variant::void_; U15 = boost::detail::variant::void_; U16 = boost::detail::variant::void_; U17 = boost::detail::variant::void_; U18 = boost::detail::variant::void_; U19 = boost::detail::variant::void_; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
c:/.../include/boost/variant/variant.hpp:1385:10: note: void boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::convert_construct(const boost::variant<U0, U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18, U19>&, long int) [with U0 = char; U1 = bool; U2 = boost::detail::variant::void_; U3 = boost::detail::variant::void_; U4 = boost::detail::variant::void_; U5 = boost::detail::variant::void_; U6 = boost::detail::variant::void_; U7 = boost::detail::variant::void_; U8 = boost::detail::variant::void_; U9 = boost::detail::variant::void_; U10 = boost::detail::variant::void_; U11 = boost::detail::variant::void_; U12 = boost::detail::variant::void_; U13 = boost::detail::variant::void_; U14 = boost::detail::variant::void_; U15 = boost::detail::variant::void_; U16 = boost::detail::variant::void_; U17 = boost::detail::variant::void_; U18 = boost::detail::variant::void_; U19 = boost::detail::variant::void_; T0_ = char; T1 = bool; T2 = boost::detail::variant::void_; T3 = boost::detail::variant::void_; T4 = boost::detail::variant::void_; T5 = boost::detail::variant::void_; T6 = boost::detail::variant::void_; T7 = boost::detail::variant::void_; T8 = boost::detail::variant::void_; T9 = boost::detail::variant::void_; T10 = boost::detail::variant::void_; T11 = boost::detail::variant::void_; T12 = boost::detail::variant::void_; T13 = boost::detail::variant::void_; T14 = boost::detail::variant::void_; T15 = boost::detail::variant::void_; T16 = boost::detail::variant::void_; T17 = boost::detail::variant::void_; T18 = boost::detail::variant::void_; T19 = boost::detail::variant::void_]
Boost. Variant, part of collection of the Boost C++ Libraries. It is a safe, generic, stack-based discriminated union container, offering a simple solution for manipulating an object from a heterogeneous set of types in a uniform manner.
In boost::variant , it computes the maximum sized object, and uses "placement new" to allocate the object within this buffer. It also stores the type or the type index. Note that if you have Boost installed, you should be able to see the source files in "any. hpp" and "variant.
boost::apply_visitor — Allows compile-time checked type-safe application of the given visitor to the content of the given variant, ensuring that all types are handled by the visitor.
boost::static_visitor is a template. The type of the return value of operator() must be specified as a template parameter. If the operator does not have a return value, a template parameter is not required, as seen in the example. The second parameter passed to boost::apply_visitor() is a boost::variant variable.
The accepted answer and the other answers do not answer the question. There are good reasons to derive from boost::variant.
boost::apply_visitor(visitor(), variant)
without jumping through hoopsHere is a working example of a type MyVariant
inheriting from boost::variant
. The code requires C++11 to inherit the (complex) constructors of boost::variant
.
Edit: Operators such as equal comparison implemented in boost::variant
do not automatically work for the derived class. This is a (unintended) consequence of how boost::variant
is implemented, it explicitly prevents comparisons to "foreign" types using templates. Operators can be enabled with explicit overloads, as shown in the example.
#include<iostream>
#include<boost/variant.hpp>
struct type_size_visitor : public boost::static_visitor<unsigned> {
template <typename T>
unsigned operator()(const T&) const { return sizeof(T); }
};
template <typename... Types>
class MyVariant : public boost::variant<Types...>
{
using base_type = boost::variant<Types...>;
public:
// inherit constructors
using base_type::base_type;
// add a new method
unsigned type_size() { return boost::apply_visitor(type_size_visitor(), *this); }
/* Inheriting operators from boost::variant does not
work as it normally would. We have to add explicit
overloads for the operators we want to use.
*/
bool operator==(const MyVariant& rhs) const {
// cast rhs to base and delegate to operator in base
return base_type::operator==(static_cast<const base_type&>(rhs));
}
};
int main() {
MyVariant<std::string, char> v;
v = 1;
std::cout << v.type_size() << " " << sizeof(char) << std::endl;
v = std::string("foo");
std::cout << v.type_size() << " " << sizeof(std::string) << std::endl;
// comparison operators need workaround shown above
MyVariant<std::string, char> a, b;
a = 1; b = 1;
assert(a == b);
}
I want an empty state
boost::variant<boost::blank, bool, long, std::string>
There. That was much easier. No need for messy inheritance.
I want to give enum types
enum Type
{
NONE,
BOOL,
LONG,
STRING
};
struct GetType : public boost::static_visitor<Type>
{
Type operator()(boost::blank) {return NONE;}
Type operator()(bool) {return BOOL;}
Type operator()(long) {return LONG;}
Type operator()(const std::string&) {return STRING;}
};
//Get the type
Type t = boost::apply_visitor(GetType(), theData);
That was easy too. Plus, if you add a new type to the variant, your code will break if you don't update GetType
to match.
The other two criteria require you to use a class, but you don't need inheritance. You need containment.
typedef boost::variant<boost::blank, std::string, long> VarType;
class MyVariant
{
public:
//Default construction will initialize with boost::blank.
MyVariant(char c) : m_var(std::string(1,c)) {}
MyVariant(const char* s) : m_var(std::string(s)) {}
MyVariant(int v) : m_var(long(v)) {}
MyVariant(long v) : m_var(long(v)) {}
VarType &operator *() {return m_var;}
const VarType &operator *() const {return m_var;}
private:
VarType m_var;
};
...
Type t = boost::apply_visitor(GetType(), *theData);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With