2014-08-29 66 views
3

我已经在Clojure(一种功能语言)编程了一段时间了,我不得不使用C++作为一个类。我一直在尝试使用我在Clojure中享受过的一些功能(例如,高阶函数,lambda表达式,参数线程,动态输入等),但我已经遇到了一些砖墙。具有模板的高阶函数?

首先,我已经实现的功能get采用两个参数:

  1. 集合(向量,列表,哈希映射等),和
  2. 索引

并返回该索引处的元素。

我还实现的功能conj采用两个参数:

  1. 集合(向量,列表,队列,等等),以及
  2. 元素/对象(无论何种类型的集合是)

并返回添加了元素的集合。在矢量的情况下,这与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的极其有限的经验,我的猜测是它不能将vector<double>转换为vector<boost::any>,尽管boost::any的明显权利要求是它可以作为几乎任何类型的替代品。

我想get函数是一般的,所以我不想使用boost::function<double (vector <double>, int)>,或任何类似的特定类型。

此外,如果从get请求的索引超出范围,我正在使用boost::optional而不是vector返回null_ptr

因为它的立场,这是我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); 
} 

等...

有关如何使forward函数正常工作的任何想法?

我也敢肯定有实现它比做元数超载,因为我有一个更有效的方式。

+0

查找一元函数和continuators,功能PROG猛击概念。 [看看它是如何在C++ 11中实现的。](http://stackoverflow.com/a/25342660/701092) – 0x499602D2 2014-08-29 15:33:49

+0

什么是编译器和版本? – 2014-08-29 15:43:41

回答

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似乎支持升压)

2

这就是我能想出:

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

相反的lambda表达式我在三个不同的变体使用完全成熟的仿函数。它支持你的例子,不需要类型擦除或类似的东西(例如boost :: any或std :: function)。

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

此外,forward功能被实现为可变参数模板,允许任何数量的功能。

该代码是未磨光的,但也许它可以给一些灵感。

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

+0

您的回复很好。安东对我来说对代码更有用,但你的想法确实有帮助。太糟糕了,无法选择两个正确的答案。谢谢! – alexandergunnarson 2014-08-30 03:11:02