累积向量的绝对值

Accumulate absolute values of a vector

本文关键字:绝对值 向量      更新时间:2023-10-16

如果我想累积std::vector的绝对值,我可以使用 lambda 计算绝对值并将其添加到std::accumulate的总和(现场演示(。

#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;大卫:没有。如果要转换和添加元素,则必须同时执行这两项操作。没有叫做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);

然而,正如这里所见,fabs 在浮点、双精度和长双精度上重载,这意味着 std::fabs 是一个重载集,而不是一个单一函数,因此不清楚你想传递哪个版本地址。这部分问题在这里有一个答案:如何指定指向重载函数的指针?

此外,如注释和其他答案中所述,累加最后一个参数期望结合两个值的二进制操作,而晶圆厂仅取一个绝对值。使用的正确算法是 C++17 的transform_reduce:

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