为什么C++运算符重载需要"至少有一个类类型的参数"?

Pen*_*ang 7 c++ operator-overloading c++11

"C++入门第5版"第14.1章读到,

运算符函数必须是类的成员或至少具有一个类类型的参数.

例如,string("hello")+"world"编译"hello"+"world"没有.当我想重载+两个C字符串时.

std::string operator+ (const char* s1, const char* s2)
Run Code Online (Sandbox Code Playgroud)

我收到以下错误.

错误:'std :: string operator +(const char*,const char*)'必须具有类或枚举类型的参数

我有两个问题.

  1. 这个限制是语言规范的一部分吗?如果是,为什么C++设计师想要这样做呢?

  2. std::string具有构造类似string (const char* s);,这意味着编译器可以做隐含类型转换char*string.当我们调用时"hello"+"world",为什么编译器不会将两个char*"s" 转换为两个字符串?毕竟,在两个std :: strings上存在重载"+". string operator+ (const string& lhs, const string& rhs);

Ker*_* SB 7

正如Bjarne在" 设计与进化"中所说,目标是使语言扩展变得容易,而不是改变它.如果您只允许重载内置类型,则会更改语言,并允许这违反了设计目标.(例如,它会鼓励形成互不相容的方言并破坏社区.)

  • @Massa:此外,这可能是C++设计如何解决您的问题的一个很好的例子:您可以编写`"abc"s +"def"s`来获取字符串.而不是改变现有的语义,明智地添加新功能(用户定义的文字)提供了一个简洁的解决方案. (3认同)

pep*_*ppe 5

这个限制是语言规范的一部分吗?如果是,为什么 C++ 设计师想要这样做?

是的。引自N3337 §13.5.6 [over.oper]:

运算符函数要么是非静态成员函数,要么是非成员函数,并且至少有一个类型为类、类的引用、枚举或枚举的引用的参数。

关于“为什么”部分,因为删除此要求意味着您可以重载已定义运算符语义的内置类型的运算符。这是完全不可取的。

例如,你认为定义这个有意义吗?

int operator+(int a, int b) { return a - b; }
Run Code Online (Sandbox Code Playgroud)

它是否允许更多人在阅读您的代码时对您的程序进行推理,还是只是一些令人惊讶的事情有效地打破了您的推理?

如果我们在游戏中获得指针会发生什么?

bool operator==(const char *str1, const char *str2) { 
    return strcmp(str1, str2) == 0;
}
Run Code Online (Sandbox Code Playgroud)

你会期望operator==现在取消引用内存吗?我不会。令人惊讶。这与标准已经对这些运营商的说法背道而驰。它打破了过去 25 年中每个 C 程序的表现。语言不应该让你做这种滥用。


rod*_*igo 5

  1. 这是语言规范的一部分吗?

是的。为什么?好吧,主要原因可能是因为重新定义标准类型的常规运算符被认为是令人困惑的。想象超载operator+(int,int)operator+(int,char*)。那将改变现有代码的含义!

您可能会争辩说,在标准类型之间存在未定义的运算符,因此可以放心地覆盖它们,例如operator*(char*,int),但这通常被认为是无用的。

而且,运算符重载必须是全局的(或在其某些成员的命名空间中(取决于参数的查找),但是对于标准类型,没有依赖的命名空间),因此希望覆盖它们的库之间的互操作性将是一个问题。恶梦。

  1. "hello" + "world":为什么编译器不将两个char *转换为两个字符串?

好吧,因为它std::operator+(const std::string&, const std::string&)已经存在,namespace std;所以默认情况下不会找到它。

您可以尝试显式调用该运算符:std::operator+("hello", "world"),但是,operator+()过载如此之多,其中有许多模板,使得调用是模棱两可的。

因此,考虑到所有这些因素,我认为一个合理的要求是至少有一个运算符为用户定义类型。考虑一下:解决了全局和名称空间问题,可以使用ADL(实际上是为此而发明的),并且不可能用现有含义重新定义运算符(我operator,()operator&(),但我想,但谁想重写这些含义)...)。