我已经用Clojure(一种函数式语言)编程了一段时间了,我必须在类中使用C ++。我一直在尝试使用我在Clojure中享受的一些功能(例如,高阶函数,lambdas,参数线程,动态类型等),但我一直在遇到一些砖墙。
首先,我实现了一个函数get
,它带有两个参数:
并返回该索引处的元素。
我还实现了一个函数conj
,它有两个参数:
并返回添加了元素的集合。在向量的情况下,这与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更有效。
答案 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似乎支持提升)