为什么 STL 数值算法使用 'op' 而不是 'op='?
Why do STL numeric algorithms use 'op' rather than 'op='?
为什么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 + *i
或cc = binary_op(acc, *i)
对其进行修改CCD_ 12。
其他数值算法也是如此。
…并且该标准基于STL
但这就是为什么它们现在被实现的原因。然而,要想了解最初的原因,还需要进一步深入兔子洞:
类型要求
对于第一个版本,采用两个参数的版本:
InputIterator
是输入迭代器的一个模型T
是Assignable的一个模型- 如果
x
是类型为T
的对象,而y
是InputIterator
的value
类型的对象,则定义了x + y
- 返回类型
x + y
可转换为T
…而STL是由…创建的
那为什么呢?让我们问问亚历山大·斯捷潘诺夫,STL背后的思想:
[A] 用户两天前在StackOverflow上提出了一个关于诸如根据
+
定义的accumulate
或inner_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+=b
和a=a+b
的争议将引发挑战:
当我们定义标准概念时,这个问题将变得非常重要,我不知道如何解决。[Stroustrup;也感谢他回答了我的问题!]
仅此而已,我希望您已经享受了C++历史的旅程。
它可能更高效,而且显然不那么冗长。
这样做的通常原因是为了最大限度地减少对底层类型的需求。如果使用+=
,那么底层类型必须支持+=
。对于像int
这样琐碎且已经存在的东西,但对于您定义的类,完全可以定义+
和=
,但不能定义复合+=
(在这种情况下,使用+=
的代码显然会失败)。
在我看来,主要原因是您可以使用标准函数对象std::plus
,并获得与operator +
相同的结果,就像在std::sort
等排序算法中使用operator <
和标准功能对象std::less
一样。
使用+而不是+=有很多原因。
A。因为这是正确的方式。Accumulate是fold,是一个对+而不是+=进行运算的函子(将函数映射到函数的函数)。为什么+而不是+=?因为+=不是一个数学函数。
B。它更高效(在现代编译器上,在所有基元类型和设计良好的对象上)对于30年前的编译器来说可能更快,但现在+更快,除非你正在积累的是一个有太多OO的可怕对象。对象生存期分析在const对象上比在引用上更容易完成。
C。它更清晰。这个原因实际上与(A)没有实质性区别比+=更清楚。清晰胜过冗长。
我想,事实是重用。STL的其余部分使用二进制运算符,而+=
是操作。所以有plus
、multiplies
等,但没有add_action
。运算符和操作是完全对称的,但如果你实现了90多种算法,在某个时候你可能不得不停止添加新概念和Ship-It.
亚历克斯说,他从来没有打算让他的STL成为所有STL开发的终点,特别是因为标准化版本只包含他最初提议的一小部分。这是一个明显的延伸。
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 在C应用程序中运行C++(带有STL)函数
- 使用2个键的cpp-stl::优先级队列排序不正确
- 在STL容器中使用模板类
- 用C++中的CPerson(类)类型的对象初始化STL矢量
- 将stl字符串缩小到小于15个字符的容量
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查函数返回类型是否与STL容器类型值相同
- STL算法函数在多个一维容器上的使用
- 在STL - C++中按成绩对学生列表进行排序?
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- λ可以适应STL吗?
- 为什么使用 NDK 不能存在不同的 stl 实现?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 使用 char 分隔符解析C++中的字符串,但将可重复的字符保留为每个解析的子字符串 (C++ STL) 中的分隔符
- 在C++中迭代 STL 集时出现奇怪的问题<CStudent>
- 如何在 C++17 STL 并行算法中处理调度?
- 为什么 STL 数值算法使用 'op' 而不是 'op='?
- c++ 11 STL列表=和!= op未定义