【问题标题】:Accumulate absolute values of a vector累加向量的绝对值
【发布时间】:2019-10-07 09:22:21
【问题描述】:

如果我想累加 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++ lambda accumulate


【解决方案1】:

C++17 之前

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

你想写的那行只告诉了如何转换元素(它不会编译,因为accumulate 需要一个函子来添加元素而不是转换它们的元素)。

TL;DR:不。如果你想转换和添加元素,你必须同时做。没有称为transform_and_accumulate的算法,所以你必须自己组合一些东西。

C++17

以上内容仅在 C++17 之前是正确的,它具有 transform_reduce 并且基本上可以满足您的需求。

【讨论】:

  • @RHertel 刚刚看到您的评论(链接已损坏)
【解决方案2】:

您希望通过晶圆厂的方式存在两个问题。第一个是微不足道的,另一个涉及更多。您显示的代码无法工作,因为您正在尝试调用 fabs 并将结果传递给 std::accumulate(a float or 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?

此外,如 cmets 和其他答案中所述,累积最后一个参数需要结合两个值的二元运算,而 fabs 只取一个的绝对值。正确使用的算法是 C++17 的transform_reduce:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多