43

据我了解,所有类型的boost.variant都被解析为真正的类型(这意味着好像 boostvariant<int, string> a; a="bla-bla"在编译后会变成string a; a="bla-bla") 所以我想知道:如何将什么类型放入 boost 变体中?

我尝试了什么:

#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

4 回答 4

37

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

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

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

解决此问题的一种方法是不直接使用变体类型,而是使用内部包含变体类型的类,然后定义使用该对象所需的任何隐式转换运算符,而无需大惊小怪。

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

于 2011-12-01T18:32:28.973 回答
19

boost.variant有一个.type()函数可以返回活动类型的 typeid,前提是你启用了 RTTI。

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

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;
于 2011-12-01T16:05:00.300 回答
11

您可以使用以下都导致 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);
}
于 2013-11-12T18:21:57.513 回答
0

您可以使用指针版本的boost::get. 本教程有这个例子:

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如果这不是当前存储在变体中的类型。如果该类型在变体的类型列表中出现多次,这将没有用,但这并不常见。

于 2020-07-09T14:58:25.323 回答