累积向量的绝对值

时间:2019-10-07 09:22:21

标签: c++ lambda accumulate

如果我想累积std::vector的绝对值,可以使用lambda来计算绝对值并将其添加到std::accumulatelive demo)的总和中。 / p>

#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吗?我可以摆脱它吗?

2 个答案:

答案 0 :(得分:6)

在C ++ 17之前

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

您要编写的行仅告诉您如何转换元素(并且不会编译,因为accumulate期望函子添加的元素不会转换元素)。

TL; DR:否。如果要转换和添加元素,则必须同时进行。没有称为transform_and_accumulate的算法,因此您必须自己组合一些东西。

C ++ 17

以上内容仅在具有transform_reduce并且基本上可以满足您需要的C ++ 17之前适用。

答案 1 :(得分:3)

您通过晶圆厂的方式有两个问题。第一个是微不足道的,另一个则涉及更多。您显示的代码无法正常工作,因为您正试图调用fab并将结果传递给std :: accumulate(float或double):

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在float,double和long double上重载,这意味着std :: fabs是一个重载集合,而不是一个函数,因此尚不清楚哪个版本满足您的需求想通过。问题的一部分在这里有一个答案:How do I specify a pointer to an overloaded function?

此外,如评论和其他答案所述,累加最后一个参数期望二进制运算将两个值组合在一起,而fab仅取一个绝对值。正确使用的算法是C ++ 17的transform_reduce

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