我想访问使用lambdas和过载创建函数(例如boost::hana::overload
)一个“递归”std::variant
一个`的std :: variant`。递归来访使用lambdas和固定点组合
假设我有一个叫做my_variant
变量类型,可以存储一个一个int
,一个float
或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
类)
我想递归访问变体打印不同的东西取决于存储的类型。这里有一个working example使用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
*/
我想在本地创建访问者为一系列的使用boost::hana::overload
和boost::hana::fix
重载lambda。
fix
是Y-combinator的实现,它可以用于实现类型推导lambda表达式中的递归。 (有关详细信息,请参阅this question。)
这是我试过了,和预期的工作:
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
返回一元通用lambda可以用作std::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)
应触发递归访问。
不幸的是,as you can see in this wandbox example,该lambda_visitor
例如编译失败,喷涌出大量的几乎不可破译的模板重的错误:
...
/usr/local/boost-1.61.0/include/boost/hana/functional/fix.hpp:74:50: error: use of 'main():: [with auto:2 = boost::hana::fix_t >; auto:3 = int]' before deduction of '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);
error: use of 'lambda_visitor' before deduction of 'auto' for(const auto& z : y) std::visit(lambda_visitor, z._v);
我在做什么错?是否有可能通过使用fix
,overload
和一组lambda来实现本地递归变体访问?
我的直觉是,lambda_visitor
本来“相当于”到struct_visitor
,这要归功于fix
提供的间接。
GCC HEAD [编译失败甚至升压::花:: fix'的'最基本的例子(http://melpon.org/ wandbox/permlink/P8B4X36hxbpv2FwS)(GCC 6.1和Clang HEAD工作正常),所以我认为这里的问题与'std :: variant'完全无关。使用libstdC++ HEAD尝试Clang HEAD会很有趣,但我不知道如何在wandbox上做到这一点,即使所有位都明显存在...... – ildjarn
您可以在“编译器选项”中设置'-stdlib = libstdC++' “ 部分。它似乎与叮当妥善编译后,摆脱iostreams。 –
“*您可以在”编译器选项“部分设置'-stdlib = libstdC++'*”您可以[但它似乎没有实际执行任何操作](http://melpon.org/wandbox/permlink/ yEQ1kdCEv8dgbbc3)...; - ] – ildjarn