为什么累积C++定义了两个模板

Why does accumulate in C++ have two templates defined

本文关键字:两个 C++ 定义 为什么      更新时间:2023-10-16

当工作可以用一个模板(具有binaryOperation和默认值求和的模板(完成时,为什么累加C++定义了两个模板? 我指的是来自 http://www.cplusplus.com/reference/numeric/accumulate/的累积声明

因为这就是标准的指定方式。

使用重载还是默认参数通常是一个品味问题。在这种情况下,超载被选择(由委员会、亚历山大·斯捷潘诺夫或碰巧负责选择的人(。

默认值比重载更受限制。例如,您可以有一个指向第一个重载的函数指针T (*)(InputIterator, InputIterator, T),如果只有一个函数(模板(具有 4 个参数,则这是不可能的。如果可能,这种灵活性可以用作使用重载而不是默认参数的参数。

确实,您会从单个模板中获得几乎相同的行为,例如

template <class InputIt, class T, class BinaryOperation = std::plus<>>
accumulate(InputIt first, InputIt last, T init, BinaryOperation op = {});

但请注意,在早期版本的C++中,这将是困难或不可能的:

  • 在 C++11 之前,函数模板不能具有默认模板参数。
  • 在 C++14 之前,std::plus<>(与std::plus<void>相同(无效:类模板只能使用一种特定的参数类型实例化。
  • accumulate模板甚至比1998年的第一个C++标准还要古老:它可以追溯到SGI STL库。当时,编译器对模板的支持相当不一致,因此建议使模板尽可能简单。

因此,保留了原来的两份声明。正如 bobah 的回答中所指出的,将它们组合成一个声明可能会破坏现有代码,因为例如代码可能使用函数指针指向三参数版本的实例化(并且函数指针不能表示默认函数参数,无论函数是否来自模板(。

有时,标准库会向现有函数添加额外的重载,但通常仅用于改进接口的特定目的,并且在可能的情况下不会破坏旧代码。 没有任何这样的理由std::accumulate.

(但请注意,标准库中的成员函数可能比非成员函数(如std::accumulate(更频繁地更改。该标准允许实现声明具有不同重载、默认参数等的成员函数,只要效果如前所述即可。这意味着首先将指向成员函数的指针指向标准库类成员或以其他方式假定非常具体的声明通常是一个坏主意。

这两个函数的动机与我们同时拥有copy函数和transform函数的原因相同,以使编码人员能够灵活地在每个元素的基础上应用函数。但也许一些现实世界的代码将有助于理解这将在哪里使用。我在编码中专业地使用了这两个截图:

累积的第一个实例可用于对范围的元素求和。例如,给定const int input[] = { 13, 42 }我可以这样做来获取input中所有元素的总和:

accumulate(cbegin(input), cend(input), 0) /* Returns 55 */

我个人最常使用 2nd实例来生成strings(因为它是 c++ 最接近join的东西(,但它也可以在添加元素之前需要特殊预处理时使用。例如:

accumulate(next(cbegin(input)), cend(input), to_string(front(input)), [](const auto& current_sum, const auto i){ return current_sum + ", " + to_string(i); }) /* Returns "13, 42"s */

在考虑我使用 2nd函数时,值得注意的是P0616R0。这个提议已经被 c++20 接受,并将移动而不是复制第一个参数到accumulate的函子中,"可以导致巨大的改进(特别是, 意味着累积strings是线性的而不是二次的(。