我开始玩Boost :: Range,以便有一个
pipeline of lazy transforms in C++.我现在的问题是如何拆分较小部分的管道.假设我有:
int main(){ auto map = boost::adaptors::transformed; // shorten the name auto sink = generate(1) | map([](int x){ return 2*x; }) | map([](int x){ return x+1; }) | map([](int x){ return 3*x; }); for(auto i : sink) std::cout << i << "\n"; }
我想用magic_transform替换前两个地图,即:
int main(){ auto map = boost::adaptors::transformed; // shorten the name auto sink = generate(1) | magic_transform() | map([](int x){ return 3*x; }); for(auto i : sink) std::cout << i << "\n"; }
怎么会写magic_transform?我抬头看了Boost::Range’s documentation,但是我不能很好的把握.
附录:我正在寻找一个这样写的类:
class magic_transform { ... run_pipeline(... input) { return input | map([](int x){ return 2*x; }) | map([](int x){ return x+1; }); };
解决方法
最困难的问题是在代码中找出返回类型. decltype和lambdas不能很好地混合(
see here),所以我们必须考虑一种替代方法:
auto map = boost::adaptors::transformed; namespace magic_transform { std::function<int(int)> f1 = [](int x){ return 2*x; }; std::function<int(int)> f2 = [](int x){ return x+1; }; template <typename Range> auto run_pipeline(Range input) -> decltype(input | map(f1) | map(f1)) { return input | map(f1) | map(f2); } } ... auto sink = magic_transform::run_pipeline(generate(1)) | map([](int x){ return 3*x; });
简单的解决方案是将lambdas粘贴到std ::函数中,因此我们可以使用decltype来推断返回类型.我在这个例子中使用了namespace magic_transform,但是如果你也愿意,你可以将这段代码修改成一个类. Here is a link使您的代码适应上述.
此外,使用std ::函数可能会在这里过度使用.相反,您可以只声明两个正常的功能(example).
我也在尝试boost :: any_range,似乎有一些不兼容的C 11羊羔等.最接近的是以下(example):
auto map = boost::adaptors::transformed; using range = boost::any_range< const int,boost::forward_traversal_tag,const int&,std::ptrdiff_t >; namespace magic_transform { template <typename Range> range run_pipeline(Range r) { return r | map(std::function<int(int)>([](int x){ return 2*x; })) | map(std::function<int(int)>([](int x){ return x+1; })); } } int main(){ auto sink = magic_transform::run_pipeline(boost::irange(0,10)) | map([](int x){ return 3*x; }); for(auto i : sink) std::cout << i << "\n"; }