Boost Variant:如何获得当前持有的类型?

时间:2011-12-01 15:44:05

标签: c++ boost boost-variant

据我所知,所有类型的boost.variant都被解析为真实类型(意思是在编译后会像variant<int, string> a; a="bla-bla"一样转为string a; a="bla-bla")所以我想知道:如何获得什么类型被加入变种?

我尝试了什么:

#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;
}

4 个答案:

答案 0 :(得分:32)

v.which()将返回当前持有的对象类型的从0开始的索引。

当您检索对象时,您的代码必须使用静态类型(为了满足get<T>函数模板)来引用(有效)动态类型对象。

您需要测试类型(使用which()type())并相应地进行分支或使用静态访问者。无论您选择哪种方式,都必须显式声明要检索的静态类型,并且必须与动态类型匹配,否则将抛出异常。

解决这个问题的另一种方法是直接使用一个包含变量类型的类,而不是直接使用变量类型,然后定义使用该对象所需的任何隐式转换运算符。

我有一个名为Dynamic C++的项目,它使用了这种技术。

答案 1 :(得分:18)

boost.variant.type() function,只要您启用了RTTI,就可以返回活动类型的typeid。

您还可以定义静态访问者,以根据变体内容的类型执行操作,例如

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;

答案 2 :(得分:9)

您可以使用以下两者导致std :: type_info对象:

  • boost :: variant的type()成员函数,
  • 可应用于任何类型或类型表达式的C ++运算符typeid(),

与成员函数std :: type_info :: operator ==一起检查boost :: variant当前存储的类型。例如,

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);
}

答案 3 :(得分:0)

您可以使用boost::get的指针版本。 tutorial的示例如下:

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;
}

因此,您可以像平常使用boost::get一样使用它,但是将指针传递给变量,如果不是当前存储在变量中的类型,则结果为nullptr的指针。如果该类型在变体的类型列表中多次出现,则没有用,但这不是很常见。