ere*_*eOn 12 c++ namespaces operator-overloading operator-keyword
可能重复:
非成员运算符重载应放在何处?
在浏览SO时,我经常会发现涉及重载/定义a std::ostream& operator<<(std::ostream& os, const Foo& foo)或a的问题或答案Foo operator+(const Foo& l, const Foo& r).
虽然我知道如何以及何时(不)编写这些操作符,但我对namespace此事感到困惑.
如果我有以下课程:
namespace bar
{
class Foo {};
}
Run Code Online (Sandbox Code Playgroud)
namespace我应该在哪个中编写不同的运算符定义?
// Should it be this
namespace bar
{
std::ostream& operator<<(std::ostream& os, const Foo& foo);
}
// Or this ?
namespace std
{
ostream& operator<<(ostream& os, const bar::Foo& foo);
}
// Or this ?
std::ostream& operator<<(std::ostream& os, const bar::Foo& foo);
Run Code Online (Sandbox Code Playgroud)
同样的问题适用于operator+.那么,这里的好习惯是什么?为什么?
Sjo*_*erd 14
规则是,在查找合适的函数重载时,会考虑当前名称空间和参数类型定义的所有名称空间.这称为参数依赖查找(ADL).
所以当你有这个代码时:
::std::ostream& os = /* something */;
const ::bar::Foo& foo = /* something */;
os << foo;
Run Code Online (Sandbox Code Playgroud)
考虑以下名称空间:
因此,您命名的所有三种可能性都将起作用,因此乍一看"足够好".
然而....
您不能在:: std中定义新函数,因此您不能将重载的运算符放在该命名空间中.(你可以在:: std中专门化模板,但这不是我们在这里做的)
其次,"当前命名空间"可能会发生变化,因此如果将函数定义放在该命名空间中,则可能无法始终找到它.
所以最后,放置重载运算符的最佳位置与Foo位于同一个命名空间中:
namespace bar
{
std::ostream& operator<<(std::ostream& os, const Foo& foo);
}
Run Code Online (Sandbox Code Playgroud)
GMa*_*ckG 12
它应该在bar命名空间中.您必须考虑构成该类接口的内容,并将它们组合在一起.
"一个类描述了一组数据以及对该数据进行操作的函数." 你的免费功能在a上运行Foo,因此它是其中的一部分Foo.它应该Foo在命名空间中分组bar.
依赖于参数的查找或ADL将找到该函数.
我们也知道我们应该更喜欢非朋友的非会员功能.这意味着,通常,您的类将具有其定义和成员函数,紧接着是在类上运行的自由函数.