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 << typeid(T).name() << "\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?
std::variant 是不是提供类似于 boost::variant<>::types 的功能?