C++ 在Boost::range中组合适配器

C++ 在Boost::range中组合适配器,c++,boost,functional-programming,boost-range,C++,Boost,Functional Programming,Boost Range,我开始玩Boost::Range以获得更好的性能。我现在的问题是如何将管道分成更小的部分。假设我有: 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; })

我开始玩Boost::Range以获得更好的性能。我现在的问题是如何将管道分成更小的部分。假设我有:

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
?我抬头看了看,但是我不能很好地理解它

附录:我想写一个这样的课程:

class magic_transform {
    ... run_pipeline(... input) {
        return input | map([](int x){ return 2*x; })
                     | map([](int x){ return x+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);
}
auto magic_transform()->decltype(boost::adapters::transformed(std::function())
{
函数retval=[](intx){return[](intx){return x+1;}(2*x);
返回boost::adapters::transformed(retval);
}
但它可能不是您想要的。:(上面代码中的笑话:2*x+1的链式lambda,基本上在实现中使用decltype来查找返回类型)

查看
http://www.boost.org/doc/libs/1_46_1/boost/range/adaptor/transformed.hpp
magic\u transform
想要返回的类型是
boost::range\u detail::transform\u holder
,其中T是函数的类型

当您使用lambdas在堆栈上执行此操作时,
T
最终会成为一些非常狭窄的类型。如果您希望在不公开所有细节的情况下传递抽象转换,那么使用
std::function
可能是合理的(将有少量的运行时开销)


希望能奏效。

最困难的问题是找出代码中的返回类型。
decltype
和lambdas不能很好地混合(),因此我们必须考虑另一种方法:

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; });

generate
的返回类型是什么?我担心您的
sink
包含对在分号处过期的临时变量的引用。
generate
的返回类型是
boost::iterator\u range
,请查看详细信息。Magic transform没有获得输入参数。您将其作为空函数编写。好的,是吗更像是一个类而不是一个函数。见上文。你的需求仍然模糊。这是你想要的管道语法吗?围绕链接lamdas的转换提供了|的功能和外部使用。你真的想要|在你的magic|u转换中,如果是,为什么?是的,链接lambdas不是我想要的:),请检查我的更新。我可以ld实际上使用了
auto
decltype
,但我想要更通用的东西。所以您需要某种管道方式(按顺序组合)一起转换并使结果成为一个转换?不仅转换,而且最终过滤和其他范围适配器。范围适配器的结果类型被记录。例如,
transformed
返回boost::transformed\u range在这里询问之前,我尝试了
decltype
,发现它对于这个应用程序来说太冗长了(你最后写了两次管道。)
any_range
,oth,只允许你指定输入和输出,对吗?现在我明白了,
any_range
指定了输出(值和引用)。很有趣。另外,你也可以对参数使用
any_range
。例如:
range run_管道(range r)
定义了一个作用于一个整数范围并返回一个整数范围的管道。@brunonery:是的,我无法使
任何\u范围
用于您的
生成(1)
示例。@brunonery:我发现您需要将迭代器标记更改为
std::forward\u迭代器\u标记
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; });
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";
}