累积向量的绝对值

Accumulate absolute values of a vector

如果我喜欢累加一个std::vector的绝对值,我可以用一个lambda来计算绝对值,然后把它加到std::accumulate的总和上(live demo) .

#include <numeric>
#include <vector>

int main (){
    std::vector<int> vec {1,2,3,-4};
    auto abs_val =[](auto val, auto sum){return sum + std::fabs(val);};
    return std::accumulate(vec.begin(), vec.end(), 0, abs_val);
}

我要写

    return std::accumulate(vec.begin(), vec.end(), 0, std::fabs());

但这不会编译,因为需要一个带有两个参数 sumvalue 的函数。

有没有更优雅的写法?我需要 lambda 吗?我可以摆脱它吗?

C++17 之前

你基本上想做两件事:变换元素然后求和。对于 std::accumulate 你必须告诉算法你想如何对元素求和,但如果你想转换元素,你需要做一些额外的事情。

您要编写的行仅说明如何转换元素(它不会编译,因为 accumulate 需要一个添加元素而不是转换元素的函子)。

TL;DR: 不行。如果你想转换和添加元素,你必须两者都做。没有算法叫transform_and_accumulate,所以你得自己组合一些东西。

C++17

以上仅适用于 C++17,它具有 transform_reduce 并且基本上可以满足您的需求。

您希望通过晶圆厂的方式有两个问题。第一个是微不足道的,另一个更复杂。您显示的代码无法正常工作,因为您正在尝试调用 fabs 并将结果传递给 std::accumulate(浮点数或双精度数):

std::accumulate(vec.begin(), vec.end(), 0, std::fabs()); //note the parens ()

因此,如果 std::fabs 只是一个函数并使用正确的签名,那么这将起作用:

std::accumulate(vec.begin(), vec.end(), 0, std::fabs);

然而,可以看出here, fabs is overloaded on float, double and long double, meaning std::fabs is an overload set, not one single function and as such it's not clear which versions address you would like to pass. That part of the question has an answer here: How do I specify a pointer to an overloaded function?

此外,正如评论和其他答案中所述,accumulate last parameter 需要一个结合两个值的二元运算,而 fabs 只取一个的绝对值。正确使用的算法是 C++17 的 transform_reduce:

std::transform_reduce(vec.begin(), vec.end(),0,std::plus<>{}, static_cast<double (*)(double)>(std::fabs));