C++ 是否允许重载运算符+;对于标准库类型和内置类型?

C++ 是否允许重载运算符+;对于标准库类型和内置类型?,c++,operator-overloading,language-lawyer,user-defined-types,C++,Operator Overloading,Language Lawyer,User Defined Types,当不存在重载时,是否允许重载运算符,例如标准库类型和内置类型的组合的operator+ 例如,在默认命名空间或用户定义的命名空间中实现以下运算符是否合法: std::string operator+(const std::string& s, int right) { ... } std::string operator+(const std::string& s, int right) { ... } 我知道在std::名称空间中实现东西有各种各样的限制,但我不清楚是否有违

当不存在重载时,是否允许重载运算符,例如标准库类型和内置类型的组合的
operator+

例如,在默认命名空间或用户定义的命名空间中实现以下运算符是否合法:

std::string operator+(const std::string& s, int right) { ... }
std::string operator+(const std::string& s, int right) { ... }
我知道在
std::
名称空间中实现东西有各种各样的限制,但我不清楚是否有违反上述规定的规则(这是否是一个好主意当然是一个完全不同的问题!)

例如,在默认命名空间或用户定义的命名空间中实现以下运算符是否合法:

std::string operator+(const std::string& s, int right) { ... }
std::string operator+(const std::string& s, int right) { ... }
是的,这样做是完全合法的。唯一的限制是在
命名空间std
中添加名称,或专门化成员函数模板或类模板,或在
std
中为类模板添加演绎指南

没有什么能阻止你写这样的东西:

namespace N {
    std::string operator+(std::string s, int ) { return s; }
}
根据标准,这是一个结构良好的程序。但是请注意,根据定义,您的运算符中不会有任何程序定义的类型,因此ADL将永远找不到它们。由于它们是通常由ADL发现的运算符,这本身可能是避免这种模式的原因:

namespace U {
    auto foo() {
        return "hello"s + 1; // error: name lookup doesn't find our operator
    }

    auto bar() {
        using namespace N;
        return "hello"s + 1; // ok: for some definition of ok
    }
}

这样写是合法的。但它不一定能满足你的需求

如果你的目标是制作<代码> SoxSnc++ 4代码/Calpic C++代码,那么它的合法性将取决于表达式的确切位置。运算符重载将使用ADL查找运算符[over.match.oper]/3.2:

非成员候选集是根据非限定函数调用中名称查找的常规规则(6.4.2)在表达式上下文中对运算符@进行非限定查找的结果,但忽略所有成员函数除外。但是,如果没有操作数具有类类型,则只有那些非成员 当T1为枚举类型时,查找集中具有类型为T1或“引用cv T1”的第一个参数的函数,或当T2为枚举类型时(如果有右操作数),具有类型为T2或“引用cv T2”的第二个参数的函数是候选函数

但由于
运算符+
与任一参数不在同一命名空间中,因此ADL查找将失败。而且非成员候选列表不会自动包含全局函数,它没有机会找到正确的
操作符+


因此,如果不打开名称空间,就无法有效地重载这样的运算符。这当然是禁止的
std

std::string
int
之间重载
操作符+
是完全可以的。标准对它的唯一限制是():

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


即使是标准库中的类型,也不能在命名空间中定义它们。

我认为答案是“否”,并且至少有一个类型必须是用户定义的,但我现在找不到该类型的引用。@Daniel std::string是用户定义的类型。本例中的用户是在标准库中实现std::string的人员。@它由实现(包括标准库)定义。我不认为“用户定义类型”是标准中定义的术语,但如果它是,并且它包括实现定义的类型,那么我对这个术语的理解是错误的。这个术语不是。事实上,有人建议澄清这一点(我目前找不到),但还没有被接受。@DanielH其中一个类型必须是类类型或枚举(或对类或枚举的引用),没有用户定义的限制。C++17现在正式发布,可能是时候使用了。如果做不到这一点,我想你至少应该用C++14来回答没有版本标记的问题。@DanielH,当我可以用C++11作为指导时,我觉得自己已经很跟上时代了,因为我在工作中仍然需要使用VS2008:)GCC 3.3对我来说很长时间。我会为一些C++11的优点而杀人。谢谢,这太完美了。有两个等价正确的答案,所以我根据时间戳选择了另一个,但这一个也没有错。等等,也许我误读了,但看起来它将在中声明的重载的名称空间中工作。你从哪里知道它忽略了全局函数?奇怪的是,它适用于我抛出的每一个编译器(gcc、clang、MSVC、icc),其中运算符在声明的同一名称空间(默认名称空间)中被调用。参考6.4.2是关于ADL的,但基于文本,它似乎同时进行非ADL和ADL查找,就像常规的非限定函数调用一样。特别是因为否则它就不需要丢弃ADL无法找到的成员函数。你误读了。Nicol从未说过它忽略了全局函数?@Barry-除非我误解了Nicol,否则他说“它不会工作,因为ADL查找将失败”。它在实践中确实工作得很好,因为非ADL查找工作得很好。因此,您可以在不打开名称空间的情况下有效地重载运算符(当然,您必须知道您的运算符在哪个名称空间中声明)。