为什么不重载std::vector的运算符+=()呢

Why not overload operator+=() for std::vector?

本文关键字:重载 std vector 为什么不 运算符      更新时间:2023-10-16

我已经开始学习C++了,所以在我缺乏知识/经验的情况下,我不知道为什么STL中还没有我要描述的对新手来说如此简单的东西。要将一个矢量添加到另一个矢量,您必须键入以下内容:

v1.insert(v1.end(), v2.begin(), v2.end());

我想知道,在现实世界中,人们是否只是超载了+=运算符,以使其不那么冗长,例如的效果

template <typename T>
void operator+=(std::vector<T> &v1, const std::vector<T> &v2) {
    v1.insert(v1.end(), v2.begin(), v2.end());
}

这样你就可以

v1 += v2;

我还设置了push_back到"+="单个元素的末尾。这些事情是不是有什么原因不应该做,或者精通C++的人特别避免做?

实际上,在这种情况下,我希望看到append()重载形式的此功能。operator+=有点模糊,你的意思是把每个向量的元素互相相加吗?或者你的意思是附加?

然而,正如我所说,我会欢迎:v1.append(v2);它很清楚,也很简单,我不知道为什么没有。

我认为主要原因是+=的语义不明显。这里有你的意思,但也有一个同样有效的意思,即相等大小向量的每个元素的元素相加。由于这种模糊性,我认为他们决定最好依靠用户直接调用insert

只有在不更改这些运算符的含义时,才应重载运算符。*

这意味着,例如,如果没有两个对象乘积的数学定义,就不要重载这些对象的乘法运算符。如果存在数学对应关系,则运算符重载可以使类更方便地使用,方法是允许方程以a*b+c的形式表示,而不是更冗长的形式(a.multiply(b)).add(c)在使用加法和乘法运算符的情况下,应以加法和乘法为目的。任何其他含义都很可能混淆其他含义。重载运算符是可以接受的(在我看来,更可取)的其他一些类型是智能指针、迭代器、复数、向量和bignum。

这源于C++的设计目标之一,即应该可以定义与内置类型一样易于使用的类。当然,你可以在类上定义一些运算符,这些运算符也不是数学概念。您可能希望重载==和!=运算符,而不是编写isEqual方法,并且可能希望重载=,因为编译器的默认赋值运算符不是您想要的。

另一方面,重载运算符来做一些意想不到的事情,比如定义^将字符串翻译成日语,这是模糊和危险的。你的程序员同事会不高兴地发现,看起来像是排他性或比较性的东西实际上是非常不同的。然后,解决方案是编写类,使其易于编写清晰可维护代码,无论这意味着使用运算符重载还是避免它。

添加两个向量太模糊,无法保证定义运算符。正如其他人所表明的那样,许多人对这意味着什么有不同的想法,而对于字符串来说,人们普遍认为将两个字符串相加意味着串联。在您的示例中,还不完全清楚是要对所有元素进行组件式添加,还是在末尾添加一个元素,或者将两个向量连接在一起。尽管这样做可能更简洁,但使用运算符重载来创建自己的编程语言并不是最好的方法。

*是的,我知道Stroustrup超载了<lt;和>>执行流操作而不是位移位。但与算术和指针运算符相比,这些运算符最初并不经常使用,可以说,现在每个人都知道如何使用cout,人们普遍认为<lt;和>>是插入器和提取器运算符。(他最初试图只使用<和>进行输入和输出,但这些运算符的含义在每个人的脑海中根深蒂固,以至于代码无法读取。)

除了其他人提到的这种语法不直观,因此容易出错之外,它还违背了一个良好的设计规则,即将通用算法应用于各种容器无关函数和容器特定算法——成员函数。除了std::string外,大多数容器都遵循这一规则,后者因其整体设计而受到Herb Sutter的抨击。