Using gcc version 5.2.0 (GCC) with --std=c++14, the following code does not compile anymore, if the commented out operator ostream in namespace MyNamespace is uncommented. Is this a bug or a feature? (Compile with g++ -c --std=c++14 x.cxx)
#include <string>
#include <iostream>
typedef std::pair<std::string, std::string> StringPair;
std::ostream& operator<<( std::ostream&, const StringPair &pair) {
std::cout <<pair.first<<"."<<pair.second;
}
namespace MyNamespace {
class MyClass {};
//std::ostream& operator<< (std::ostream&, const MyClass &);
void xxx ();
}
void MyNamespace::xxx () {
StringPair pair;pair.first="1";pair.second="2";
std::cout <<pair<<std::endl;
}
The error-message i get with the operator << uncommented is:
x.cxx: In function ‘void MyNamespace::xxx()’:
x.cxx:18:13: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘StringPair {aka std::pair<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >}’)
std::cout <<pair<<std::endl;
^
As stated here, this is an example of name hiding. By defining operator<<
in namespace MyNamespace
all the definitions from the higher namespaces (like global) are hidden.
Note that as stated here:
[...]this feature doesn't interfere with Koenig lookup [...], so IO operators from
std::
will still be found.
The solution is to refer to the overload in the other namespace with the using
directive, as described here and here. This was mentioned in the comments by Michael Nastenko.
Thus using ::operator<<;
, with ::
referring to the global namespace.
Thus the code will become:
#include <string>
#include <iostream>
typedef std::pair<std::string, std::string> StringPair;
std::ostream& operator<<(std::ostream& os, const StringPair &pair) {
os << pair.first << '.' << pair.second;
return os;
}
namespace MyNamespace {
class MyClass {};
using ::operator<<;
std::ostream& operator<< (std::ostream&, const MyClass &);
void xxx();
}
void MyNamespace::xxx() {
StringPair pair("1","2");
std::cout<<pair<<std::endl;
}
int main() {
MyNamespace::xxx();
return 0;
}