为什么 STL 数值算法使用 'op' 而不是 'op='?

Why do STL numeric algorithms use 'op' rather than 'op='?

本文关键字:op STL 算法 为什么      更新时间:2023-10-16

为什么std::numeric算法似乎更喜欢op而不是op=?例如,以下是LLVM中std::accumulate的实现:

template <class _InputIterator, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
_Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
    for (; __first != __last; ++__first)
        __init = __init + *__first;
    return __init;
}

如果使用+=运算符实现,这是否可能会更高效/更少详细/更好?

在标准中是这样定义的

该标准是根据+而非+=:定义的

26.7.2累计[accumulate]

template <class InputIterator, class T>
  T accumulate(InputIterator first, InputIterator last, T init);
template <class InputIterator, class T, class BinaryOperation>
  T accumulate(InputIterator first, InputIterator last, T init,
               BinaryOperation binary_op);

效果:通过使用初始值init初始化累加器acc来计算其结果,然后为范围内的每个迭代器i使用acc = acc + *icc = binary_op(acc, *i)对其进行修改CCD_ 12。

其他数值算法也是如此。

…并且该标准基于STL

但这就是为什么它们现在被实现的原因。然而,要想了解最初的原因,还需要进一步深入兔子洞:

类型要求

对于第一个版本,采用两个参数的版本:

  • InputIterator是输入迭代器的一个模型
  • T是Assignable的一个模型
  • 如果x是类型为T的对象,而yInputIteratorvalue类型的对象,则定义了x + y
  • 返回类型x + y可转换为T

…而STL是由…创建的

那为什么呢?让我们问问亚历山大·斯捷潘诺夫,STL背后的思想:

[A] 用户两天前在StackOverflow上提出了一个关于诸如根据+定义的accumulateinner_product而不是CCD_ 26(ISO C++11第26.7节)。

我试图找到这个决定背后的一些理由,但即使SGI页面上的版本没有提到任何关于这方面的内容操作员的特定选择。

是否仅选择了运算符(a=a+b而非a+=b)根据你的个人喜好,正如一些评论所认为的那样?是a+b当时写操作的更自然的方式是什么?还是只是a=a+b和a=bin_op(a,b)之间的对称性问题?

--[Zeta]

现在,在你阅读他的答案之前,请记住,他大约在30年前开始写一个通用库,他和孟·李的第一份文件《标准模板库》将于今年10月迎来20周年纪念。事不宜迟,我提出他的答案:

我怀疑这是a=a+b和a=bin_op(a,b)之间的对称问题,但我真的不记得了。我本应该写一份理由文件,说明STL中不同设计选择之间的所有推理,但我没有。很抱歉

(如果Stepanov偶然读到这篇文章:再次感谢你的回答!)

我个人认为Common Lisp的reduce的灵感是另一个因素,但这只是猜测。

从中可以学到什么

有时,标准中的决定是基于个人偏好和优雅。例如,如果Stroustrup编写了STL,他会"强烈倾向于使用a+=b作为更直接的意图表达,通常比a=a+b更快"。然而,我不得不承认,a=a+b和a=bin_op(a,b)之间的对称性有其自身的美。

也就是说,a+=ba=a+b的争议将引发挑战:

当我们定义标准概念时,这个问题将变得非常重要,我不知道如何解决。[Stroustrup;也感谢他回答了我的问题!]

仅此而已,我希望您已经享受了C++历史的旅程。

它可能更高效,而且显然不那么冗长。

这样做的通常原因是为了最大限度地减少对底层类型的需求。如果使用+=,那么底层类型必须支持+=。对于像int这样琐碎且已经存在的东西,但对于您定义的类,完全可以定义+=,但不能定义复合+=(在这种情况下,使用+=的代码显然会失败)。

在我看来,主要原因是您可以使用标准函数对象std::plus,并获得与operator +相同的结果,就像在std::sort等排序算法中使用operator <和标准功能对象std::less一样。

使用+而不是+=有很多原因。

A。因为这是正确的方式。Accumulate是fold,是一个对+而不是+=进行运算的函子(将函数映射到函数的函数)。为什么+而不是+=?因为+=不是一个数学函数。

B。它更高效(在现代编译器上,在所有基元类型和设计良好的对象上)对于30年前的编译器来说可能更快,但现在+更快,除非你正在积累的是一个有太多OO的可怕对象。对象生存期分析在const对象上比在引用上更容易完成。

C。它更清晰。这个原因实际上与(A)没有实质性区别比+=更清楚。清晰胜过冗长。

我想,事实是重用。STL的其余部分使用二进制运算符,而+=操作。所以有plusmultiplies等,但没有add_action。运算符和操作是完全对称的,但如果你实现了90多种算法,在某个时候你可能不得不停止添加新概念和Ship-It.

亚历克斯说,他从来没有打算让他的STL成为所有STL开发的终点,特别是因为标准化版本只包含他最初提议的一小部分。这是一个明显的延伸。