0

我有一个对我很有效的功能:

template <typename __container, typename __callback = std::function <
    void (typename __container::value_type, typename __container::value_type)>
>
int reduce(__container &&container, __callback &&callback)
{
    auto current = container.begin();

    for (auto value : container)
        *current = callback(*current, value);

    return *current;
};


int result = functional::reduce(vector, [](const int current, const int next) -> int {
    return current + next;
});

std::cout << result; // 10

现在,我要统一一个:

template <typename __container, typename __callback = std::function <
    void (typename __container::value_type, typename __container::value_type)>
>
auto reduce(__container &&container, __callback &&callback) ->
 decltype(__container::value_type);

但是我收到以下错误:

reduce.cpp:61:9: error: no matching function for call to 'reduce'
int i = reduce(vector, [](const int current, const int next) -> int {
        ^~~~~~~~~~~~~~~~~~
reduce.hpp:69:7: note: candidate template ignored: substitution failure [with __container = std::__1::list<int, std::__1::allocator<int>> &, __callback = <lambda at
      nott.cpp:61:36>]
        auto reduce(__container &&container, __callback &&callback) -> decltype(__container::value_type)
             ^
1 error generated.
make: *** [build] Error 1

如何设置通用返回类型?

更新:

template <typename __container, typename __callback>
auto reducef(const __container& input, __callback callback) ->
decltype(callback(std::declval<typename __container::value_type>(), std::declval<typename __container::value_type>()))
{
    decltype(
        callback(
            std::declval<typename __container::value_type>(),
            std::declval<typename __container::value_type>()
        )
    ) result{};

    return std::accumulate(input.begin(), input.end(), result, callback);
};
4

2 回答 2

4

这个签名是错误的:

auto reduce(__container &&container, __callback &&callback) ->
 decltype(__container::value_type);

value_type是一个类型,你 decltype 它。这就像decltype(int). 但是,__container::value_type也不起作用,因为编译器不知道这value_type是一种类型。你必须明确地使用typename

auto reduce(__container &&container, __callback &&callback) ->
 typename __container::value_type;

还有一些可以改进的地方:修改编译器的前端元素以减少它。我想你想做这样的事情:

auto current = *container.begin(); // added *

for (auto value : container)
    current = callback(*current, value); // removed *

return current; // removed *

还有另一个错误:第一个值减少了两次。

assert(!container.empty());
auto current = *container.begin();

for (auto it=container.begin()+1; it!=container.end(); ++it)
    current = callback(current, *it);

return current;

进一步改进:使用迭代器代替范围:

template <typename Iter, typename Callback>
T reduce(Iter start, Iter end, Callback&& F)
{
    assert(start != end);
    auto current = *start;
    while (++start != end)
      current = callback(current, *it);
    return *current;
};

下一个问题:为什么限制不接受空范围?为此使用初始值。

template <typename Iter, typename T, typename Callback>
T reduce(Iter start, Iter end, T init, Callback&& F)
{
    while (start != end)
      init = callback(init, *it++);
    return init;
};

而且,令人惊讶的是,这正是 的定义std::accumulate

于 2013-01-08T18:09:19.357 回答
1

正如其他人所指出的,您不需要decltype. 你也不需要auto. 保持代码与您的代码接近(因为风格不是手头的问题),这是一个工作版本:

#include <iostream>
#include <vector>

template <typename Container, typename Callback>
typename Container::value_type reduce(Container &container, Callback &&cb) {
    auto current = container.begin();

    for (auto value : container)
        *current = cb(*current, value);

    return *current;
}

int main() {
    std::vector<int> v = {1, 2, 3};

    int result = reduce(v, [](const int current, const int next) -> int {
         return current + next;
    }); 

    std::cout << "result = " << result << std::endl;
}
于 2013-01-08T18:18:17.373 回答