10

我正在尝试使用 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)>'

在我看来, usingstd::function不是定义f. 我该如何纠正?

4

3 回答 3

15

您的代码不是很通用。不需要function,vector或任何类似的东西。通常,在 C++ 中,函数将位于参数列表的末尾(对于 lambda 尤其重要,因为它们可能很大)。

所以最好这样写(即:更标准):

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

或者你可以使用std::accumulatewhich 做完全相同的事情

于 2013-03-17T07:31:21.423 回答
4

我不确定为什么这个模板会失败,但是切换到对函数使用模板参数而不是std::function<>似乎工作得很好。

template<typename T, typename F>
T foldl(F f, T initial, std::vector<T> items) {
于 2013-03-17T07:25:38.473 回答
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具有适当类型参数的 a,但编译器不知道什么模板参数T可以使其可转换。(我们碰巧知道T=int会起作用,但没有通用的方法来解决它。)所以它无法编译它。

于 2013-03-18T00:03:13.450 回答