我想访问一个使用 lambdas 和重载创建函数(例如)的“递归” 。std::variant
boost::hana::overload
假设我有一个名为的变体类型my_variant
,它可以存储一个 an int
、 afloat
或 a vector<my_variant>
:
struct my_variant_wrapper;
using my_variant =
std::variant<int, float, std::vector<my_variant_wrapper>>;
struct my_variant_wrapper
{
my_variant _v;
};
(我正在使用包装my_variant_wrapper
类来递归定义变体类型。)
我想根据存储的类型递归地访问打印不同内容的变体。这是一个使用-based 访问者的工作示例:struct
struct struct_visitor
{
void operator()(int x) const { std::cout << x << "i\n"; }
void operator()(float x) const { std::cout << x << "f\n"; }
void operator()(const std::vector<my_variant_wrapper>& x) const
{
for(const auto& y : x) std::visit(*this, y._v);
}
};
std::visit
使用上述访问者调用会打印所需的输出:
my_variant v{
std::vector<my_variant_wrapper>{
my_variant_wrapper{45},
std::vector<my_variant_wrapper>{
my_variant_wrapper{1}, my_variant_wrapper{2}
},
my_variant_wrapper{33.f}
}
};
std::visit(struct_visitor{}, v);
// Prints:
/*
45i
1i
2i
33f
*/
我想在本地创建访问者作为一系列重载的 lambda,使用boost::hana::overload
和boost::hana::fix
将访问者本地创建为一系列重载的 lambda 。
fix
是Y-combinator的一个实现,可用于在类型推导的 lambda 中实现递归。(见这个问题。)
这是我尝试过的,并期望工作:
namespace bh = boost::hana;
auto lambda_visitor = bh::fix([](auto self, const auto& x)
{
bh::overload(
[](int y){ std::cout << y << "i\n"; },
[](float y){ std::cout << y << "f\n"; },
[&self](const std::vector<my_variant_wrapper>& y)
{
for(const auto& z : y) std::visit(self, z._v);
})(x);
});
我的推理如下:
boost::hana::fix
返回一个可以用作访问者的一元通用 lambdastd::variant
。boost::hana::fix
接受一个二进制通用 lambda,其中第一个参数是允许 lambda 递归的一元函数,第二个参数是 lambda 主体的初始参数。调用
boost::hana::overload
内部所有可能类型的处理程序my_variant
会创建某种访问者,相当于struct_visitor
.在重载中使用
self
而不是应该允许递归正常工作。lambda_visitor
const std::vector<my_variant_wrapper>&
立即调用创建的重载
bh::overload(...)(x)
应该触发递归访问。
不幸的是,正如您在这个wandbox示例中看到的那样,该lambda_visitor
示例无法编译,产生了许多几乎无法辨认的大量模板错误:
...
/usr/local/boost-1.61.0/include/boost/hana/functional/fix.hpp:74:50: 错误:使用'main():: [with auto:2 = boost::hana::fix_t >; auto:3 = int]' 在扣除 'auto' 之前 { return f(fix(f), static_cast(x)...); }
...
该错误似乎类似于我不使用时会得到的错误boost::hana::fix
:
auto lambda_visitor = bh::overload(
[](int y){ std::cout << y << "i\n"; },
[](float y){ std::cout << y << "f\n"; },
[](const std::vector<my_variant_wrapper>& y)
{
for(const auto& z : y) std::visit(lambda_visitor, z._v);
});
std::visit(lambda_visitor, v);
错误:在扣除 'auto' 之前使用 'lambda_visitor' for(const auto& z : y) std::visit(lambda_visitor, z._v);
我究竟做错了什么?是否可以使用,来实现局部递归变体访问fix
overload
和一组 lambda
lambda_visitor
我的直觉是,struct_visitor
由于fix
.