我开始玩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; });
};
答案 0 :(得分:5)
最困难的问题是找出代码中的返回类型。 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::function
中,这样我们就可以使用decltype
来推断返回类型。我在示例中使用了名称空间magic_transform
,但如果您愿意,也可以将此代码调整为类。 Here is a link使您的代码适应上述情况。
此外,使用std::function
可能会有点矫枉过正。相反,你可以改为声明两个普通函数(example)。
我也在试验boost::any_range
,似乎与C + 11 lambdas等有些不兼容。我能得到的最接近的是(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";
}
答案 1 :(得分:1)
我认为会奏效:
auto magic_transform()->decltype(boost::adaptors::transformed(std::function<int(int)>())
{
std::function<int(int)> retval = [](int x){ return [](int x){ return x+1; }(2*x);
return boost::adaptors::transformed(retval);
}
但它可能不是你想要的。 :)(以上代码中的笑话:链接lambda为2 * x + 1,使用decltype基本上实现查找返回类型),
查看http://www.boost.org/doc/libs/1_46_1/boost/range/adaptor/transformed.hpp
的源代码,magic_transform
想要返回的类型是boost::range_detail::transform_holder<T>
,其中T是函数的类型。
当您使用lambdas在堆栈上执行此操作时,T
最终会成为一种非常狭窄的类型。如果您希望在不暴露所有细节的情况下传递抽象转换,则使用std::function<outtype(intype)>
可能是合理的(将会有一个小的运行时开销)。
希望有效。