带模板的高阶函数?

时间:2014-08-29 15:26:36

标签: c++ functional-programming

我已经用Clojure(一种函数式语言)编程了一段时间了,我必须在类中使用C ++。我一直在尝试使用我在Clojure中享受的一些功能(例如,高阶函数,lambdas,参数线程,动态类型等),但我一直在遇到一些砖墙。

首先,我实现了一个函数get,它带有两个参数:

  1. 集合(矢量,列表,哈希映射等)和
  2. 索引
  3. 并返回该索引处的元素。

    我还实现了一个函数conj,它有两个参数:

    1. 集合(矢量,列表,队列等)和
    2. 元素/对象(集合的任何类型)
    3. 并返回添加了元素的集合。在向量的情况下,这与push_back大致相同。

      现在,我希望能够使用高阶函数“转发”或“线程化”参数,如下所示:

      using std::vector;
      vector<double> my_vec;
      
      forward(my_vec,    // take "my_vec"
              conj(0.1), // "push" the value of 0.1 to the back of "my_vec"
              get(0),    // retrieve the first value
              inc);      // increment that value
      

      它与inc(get(conj(my_vec, 0.1), 0);相同,但很多(!)更具可读性。

      在这种情况下,forward的返回值应为1.1。

      为了使forward函数起作用,初始参数之后的参数需要都是高阶函数。也就是说,它们需要类似于以下工作:

      template<typename Func>
      Func get(int i){
        return [i](vector<boost::any> coll)
                 -> boost::optional<boost::any> {
                   return get(coll, i);
                 };
      }
      

      但是,编译器无法推断出要返回的lambda函数的类型。此外,根据我对boost::any的极其有限的经验,我的猜测是,尽管有明显的{{1}声明,它仍然无法将vector<double>转换为vector<boost::any>。它几乎可以替代任何类型。

      我希望boost::any函数是通用的,因此我不想使用get或任何类似的特定类型。

      此外,如果boost::function<double (vector <double>, int)>请求的索引超出范围,我正在使用boost::optional而不是vector来返回null_ptr

      就目前而言,这是get函数的外观:

      forward

      等。 ...

      有关如何使此template <typename T1> optional<T1> forward (T1 expr1){ return expr1; } template <typename T1, typename T2> optional<T1> forward (T1 expr1, T2 expr2){ return forward(expr2(expr1)); } template <typename T1, typename T2, typename T3> optional<T1> forward (T1 expr1, T2 expr2, T3 expr3){ return forward(expr2(expr1), expr3); } 函数正常工作的任何想法?

      我也非常确定实现它的方法比执行arity-overloading更有效。

2 个答案:

答案 0 :(得分:2)

我能想出的是:

http://coliru.stacked-crooked.com/a/039905c5deff8dcf

我使用三种不同变体的完全成熟的仿函数代替lambdas。它支持你的例子,不需要类型擦除等(例如boost :: any或std :: function)。

boost::optional<double> result = forward(my_vec, conj(0.1), get(0), inc);

此外,forward函数实现为可变参数模板,允许任意数量的函数。

代码是未经修改的,但也许它可以提供一些灵感。

编辑:Anton是绝对正确的,我对前锋的实施不必要地复杂化。上面的链接现在指向他修改后的代码版本。

答案 1 :(得分:2)

只是Horstling答案的补充,实际上forward可以更容易实现:

template <typename Value>
Value forward(Value v) {
    return v;
}

template <typename Value, typename Func, typename... Funcs>
auto forward(Value v, Func f, Funcs... fs) -> decltype(forward(f(v), fs...)) {
    return forward(f(v), fs...);
}

而且C ++ 14使事情变得更加甜蜜了:

template <typename Value>
Value forward(Value v) {
    return v;
}

template <typename Value, typename Func, typename... Funcs>
decltype(auto) forward(Value v, Func f, Funcs... fs) {
    return forward(f(v), fs...);
}

查看完整代码here(Coliru似乎支持提升)