boost::variant gettor-visitor: 保存返回的引用

Posted

技术标签:

【中文标题】boost::variant gettor-visitor: 保存返回的引用【英文标题】:boost::variant gettor-visitor: saving returned references 【发布时间】:2017-02-24 14:21:10 【问题描述】:

我试图为boost::variant 编写一个访问者,它接受一个类型的参数包并为每种类型生成一个operator()。虽然调用了正确的函数,但在尝试将访问者获取的对象保存在变量中时,我仍然遇到错误。

我的访客是这样的:

#include <boost/variant.hpp>
#include <iostream>

template <class T>
class GenericGettorSpecialization

public:
    const T& operator()(T& t)
    
        std::cout << typeid(T).name() << "\n";
        return t;
    
;

template <class...>
class GenericGettorSpecializationDriver;

template <>
class GenericGettorSpecializationDriver<>

public:
    struct dummy
    
    ;
    const dummy& operator()(const dummy&);
;

template <class Head, class... Tail>
class GenericGettorSpecializationDriver<Head, Tail...>
  : protected GenericGettorSpecializationDriver<Tail...>,
    protected GenericGettorSpecialization<Head>

public:
    using GenericGettorSpecializationDriver<Tail...>::operator();
    using GenericGettorSpecialization<Head>::operator();
;

template <class Head, class... Tail>
struct GenericGettor
  : boost::static_visitor<>,
    protected GenericGettorSpecializationDriver<Head, Tail...>

public:
    using GenericGettorSpecializationDriver<Head, Tail...>::operator();
;

您可以在调用运算符中输入std::cout &lt;&lt; typeid(T).name() &lt;&lt; "\n"; 进行调试。

现在我像这样测试它:

int
main()

    boost::variant<std::string, int, double> v;
    GenericGettor<std::string, int, double>  g;

    v = "some string";
    boost::apply_visitor(g, v); // prints "NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"

    v = 10;
    boost::apply_visitor(g, v); // prints "i"

    v = 7.3;
    boost::apply_visitor(g, v); // prints "d"

    auto x = boost::apply_visitor(g, v); // throws compile time error  "error: variable has incomplete type 'void'"

显然boost::apply_vistor 返回void,但是我如何从variant 中获取引用?

【问题讨论】:

每个变量在编译时都必须有一个明确的类型。变体在任意执行点的内容直到运行时才知道。如果你想从一个变体中提取一个对象(如果类型在运行时不匹配则得到一个异常),使用boost::get 但是如果我不知道变体当前拥有的类型怎么办?在 boost 文档中,访问者在这种情况下发挥了作用,但令人困惑的是,他们不使用访问者来获取任何东西,而是操纵变体中的值:boost.org/doc/libs/1_61_0/doc/html/variant/… 是的,它就是这样工作的。访问者每个可能的类型都包含一个重载,apply_visitor 调用正确的重载。从那时起,您就知道重载中的静态类型——但它不能再冒泡了。如果要检索特定的静态类型,则需要get。您如何使用这两个工具来实现您的程序取决于您希望用它们做什么。 嗯,我最初想要实现的是拥有一个 gettor 对象gettor,它接收与它应该处理的变体相同的类型作为模板参数。然后在将该类型的变体传递给某个函数get_value(如gettor.get_value(variant_instance))时,它将返回该变体所持有的值。但我被困在“冒泡”这一步。 好吧,遗憾的是,这种语法是不可能的,因为get_value 的返回类型无法在编译时确定。您可以返回另一个类型擦除的对象,例如 boost::any 或多态实例,但您将无法静态检索包含的类型。 【参考方案1】:

这样的吸气剂已经存在:boost::get<> function template。

但是,请记住,变体内容是在运行时设置的,因此在编译时是绝对不可能知道的。

这就是为什么你应该告诉 get 函数模板你希望它返回什么类型 - 如果变体在那个时间点不包含它,它会抛出异常。

或者,您可以使用variant::which() 成员函数,它返回当前类型的索引 - 这也是一个运行时值。

【讨论】:

以上是关于boost::variant gettor-visitor: 保存返回的引用的主要内容,如果未能解决你的问题,请参考以下文章

Boost::Variant 和其中的 function_types:如何将函数放入 Boost::variant?

boost::variant:递归向量类型的奇怪行为

std::variant 是不是提供类似于 boost::variant<>::types 的功能?

使用 boost::mpl 获取 boost::variant 的类型索引

boost::variant 递归问题

boost::variant 如何存储引用?