我正在尝试使用C ++ 11中提供的新匿名函数编写泛型折叠函数,这就是我所拥有的:
template<typename T>
T foldl(std::function<T(T,T)> f, T initial, std::vector<T> items) {
T accum = initial;
for(typename std::vector<T>::iterator it = items.begin(); it != items.end(); ++it) {
accum = f(accum, (*it));
}
return accum;
}
以下尝试使用它:
std::vector<int> arr;
arr.assign(8, 2);
foldl([] (int x, int y) -> int { return x * y; }, 1, arr);
导致错误:
main.cpp:44:61: error: no matching function for call to 'foldl(main(int, char**)::<lambda(int, int)>, int, std::vector<int>&)'
main.cpp:44:61: note: candidate is:
main.cpp:20:3: note: template<class T> T foldl(std::function<T(T, T)>, T, std::vector<T>)
main.cpp:20:3: note: template argument deduction/substitution failed:
main.cpp:44:61: note: 'main(int, char**)::<lambda(int, int)>' is not derived from 'std::function<T(T, T)>'
在我看来,使用std::function
并不是定义f
类型的正确方法。我怎么能纠正这个?
答案 0 :(得分:15)
您的代码不是很通用。无需function
,vector
或任何此类内容。通常,在C ++中,函数会出现在参数列表的末尾(对于lambdas来说尤其重要,因为它们可能很大)。
所以写这个会更好(即:更标准):
template<typename Range, typename Accum>
typename Range::value_type foldl(const Range &items, const typename Range::value_type &initial, Accum f)
{
typename Range::value_type accum = initial;
for(const auto &val : items) {
accum = f(accum, val);
}
return accum;
}
或者你只能use std::accumulate
完全相同的事情。
答案 1 :(得分:4)
我不确定为什么这个模板失败,但转换为使用函数的模板参数而不是std::function<>
似乎工作得非常好。
template<typename T, typename F>
T foldl(F f, T initial, std::vector<T> items) {
答案 2 :(得分:2)
如果您只是先将其转换为std::function
,然后使用它,那么它将起作用:
std::vector<int> arr;
arr.assign(8, 2);
std::function<int(int,int)> f = [] (int x, int y) -> int { return x * y; };
foldl(f, 1, arr);
问题是lambda与std::function
的类型不同。每个lambda都是一个单独的类型。虽然lambda(和所有其他函数对象)可以转换为具有适当类型参数的std::function
,但编译器不知道T
的哪个模板参数可以使其可转换。 (我们碰巧知道T
= int
会起作用,但没有通用的方法来解决它。)所以它无法编译它。