【发布时间】: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或多态实例,但您将无法静态检索包含的类型。
标签: c++ boost visitor-pattern boost-variant