相关文章推荐
留胡子的扁豆  ·  sql ...·  2 天前    · 
不拘小节的汉堡包  ·  String.prototype.trim( ...·  18 小时前    · 
要出家的小熊猫  ·  Java ...·  13 小时前    · 
兴奋的口罩  ·  python之subprocess ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

As I understood all types of boost.variant are parsed into real types (meaning as if boost variant<int, string> a; a="bla-bla" would after compilation turn into string a; a="bla-bla" ) And so I wonder: how to get what type was put into boost variant?

What have I tried:

#include <boost/variant.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
int main()
    typedef boost::function<double (double x)> func0;
    typedef boost::function<double (double x, double y)> func1;
    typedef boost::variant<int, func0, func1> variant_func;
    func1 fn = std::plus<double>();
    variant_func v(fn);
    std::cout << boost::get<func1>(v)(1.0, 1.0) << std::endl; // this works
    //std::cout << boost::get<v::type>(v)(1.0, 1.0) << std::endl; // this does not compile with many errors
    // std::cout << (v)(1.0, 1.0) << std::endl; // this fails with Error    1   error C2064: term does not evaluate to a function taking 2 arguments
    std::cin.get();
    return 0;

v.which() will return the 0-based index of the type of the object currently held.

When you are retrieving the object your code must use a static type (in order to satisfy the get<T> function template) to refer to an (effectively) dynamically typed object.

You need to either test for the type (using which() or type()) and branch accordingly or use a static visitor. No matter which way you choose, you have to explicitly state the static type that you want to retrieve and it has to match the dynamic type or an exception will be thrown.

One way around this problem is instead of using a variant type directly, use a class which contains a variant type internally and then defines any implicit conversion operators necessary to use the object with minimum fuss.

I have a project called Dynamic C++ which uses this technique.

No. You need to use the get<T>() syntax or static visitor to retrieve the contents of a variant. – Ferruccio Dec 1, 2011 at 18:56 No, it has a fixed set of types. But it's pretty simple, although tedious, to add new types. Especially if you want to allow operations between types. – Ferruccio Dec 1, 2011 at 19:44 +1 for dynamic C++, it isn't my thing but I gave it a look and it looks very clean. Well done! – sehe Dec 1, 2011 at 22:24

boost.variant has a .type() function which can return the typeid of the active type, provided you've enabled RTTI.

You could also define a static visitor to perform actions depending on the type of content of the variant, e.g.

struct SomeVisitor : public boost::static_visitor<double>
    double operator()(const func0& f0) const { return f0(1.0); }
    double operator()(const func1& f1) const { return f1(1.0, 1.0); }
    double operator()(int integer) const { return integer; }
std::cout << boost::apply_visitor(SomeVisitor(), v) << std::endl;
                @myWallJSON: No, because the template argument must be a type, known at compile time, not a run-time typeid object.
– Mike Seymour
                Dec 1, 2011 at 16:24
                @myWallJSON: The stored value is best accessed with a static_visitor as shown above. If you use get, then it means that you know statically which type is currently stored, or you try to get the value as a type and then deal with the NULL pointer or exception. - RTTI results cannot be used for any compile-time things (such as casts). A typeid is an object containing run-time description of a type, it does not yield a typename that can be used at compile-time.
– UncleBens
                Dec 1, 2011 at 16:28
                @myWallJSON: You can do boost::get<X>(variant)(1.0, 1.0); but you better wrap it in a try block, because if variant is not storing an object of type X, an exception will be thrown.
– UncleBens
                Dec 1, 2011 at 16:34
  • the type() member function of boost::variant,
  • the C++ operator typeid() that can be applied to any type or typed expression,
  • together with the member function std::type_info::operator==, to check which type the boost::variant is currently storing. For example,

    boost::variant<int, bool, std::string> container;
    container = "Hello world";
    if (container.type() == typeid(std::string)) {
        std::cout << "Found a string: " << boost::get<std::string>(container);
    else if (container.type() == typeid(int)) {
        std::cout << "Found an int: " << boost::get<int>(container);
                    Nope! This will crash and burn if a vector has been included in the variant. ie variant<vector<int>, int > >. Use which() instead as Ferruccio indicates.
    – TimZaman
                    Jun 1, 2014 at 16:30
                    I tried with boost::variant<vector<int>, int> on MSVS 2013 and it worked. What compiler did you try it with? Can you explain your reasons for thinking that it shouldn't work for some cases?
    – richardr
                    Jun 1, 2014 at 17:08
    

    You can use the pointer version of boost::get. The tutorial has this example:

    void times_two( boost::variant< int, std::string > & operand )
        if ( int* pi = boost::get<int>( &operand ) )
            *pi *= 2;
        else if ( std::string* pstr = boost::get<std::string>( &operand ) )
            *pstr += *pstr;
    

    So you use it like you normally would use boost::get but pass a pointer to a variant instead, and the result is a pointer which is nullptr if that is not the type currently stored in the variant. It's not useful if that type appears more than once in the list of types in the variant, but that is not very common.

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.