Possible Duplicate:
Where should non-member operator overloads be placed?
While browsing on SO, I often find questions or answer that involves overloading/defining a std::ostream& operator<<(std::ostream& os, const Foo& foo)
or a Foo operator+(const Foo& l, const Foo& r)
.
While I know how and when (not) to write these operators, I'm confused about the namespace
thing.
If I have the following class:
namespace bar
{
class Foo {};
}
In which namespace
should I write the different operator definitions ?
// 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);
The same question applies for the operator+
. So, what is the good practice here and why ?
It should be in the bar
namespace. You must consider what makes up the interface for the class, and group those together.
"A class describes a set of data along with the functions that operate on that data." Your free function operates on a Foo
, therefore it is part of Foo
. It should be grouped with Foo
in the namespace bar
.
Argument-dependent lookup, or ADL, will find the function.
We also know that we should prefer non-friend non-member functions. What this means is that, in general, your classes will have their definition and member functions, followed immediately by free functions which operate on the class.
The rule is that, when looking for a suitable function overload, both the current namespace and all namespaces of the argument type definitions are considered. This is called Argument Dependent Lookup (ADL).
So when you have this code:
::std::ostream& os = /* something */;
const ::bar::Foo& foo = /* something */;
os << foo;
The following namespaces are considered:
So all three possibilities you named, will work and thus are 'good enough' on first glance.
However....
You are not allowed to define new functions in ::std, so you can't put your overloaded operator in that namespace. (You are allowed to specialize templates in ::std, but that's not what we are doing here)
Secondly, the "current namespace" may change, so if you put your function definition in that namespace, it might not always be found.
So in the end, the best place to put the overloaded operator is in the same namespace as Foo:
namespace bar
{
std::ostream& operator<<(std::ostream& os, const Foo& foo);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With