命名空间中的 ostream 运算符 << 隐藏了其他 ostream::operator
ostream operator << in Namespace hides other ostream::operator
使用带有 --std=c++14 的 gcc 版本 5.2.0 (GCC),如果命名空间 MyNamespace 中被注释掉的运算符 ostream 未被注释掉,则以下代码将不再编译。这是错误还是功能? (用 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;
}
我得到的操作符 << 未注释的错误消息是:
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;
^
如所述here, this is an example of name hiding。通过在命名空间 MyNamespace
中定义 operator<<
,来自更高命名空间(如全局)的所有定义都被隐藏。
请注意,如前所述here:
[...]this feature doesn't interfere with Koenig lookup [...], so IO operators from std::
will still be found.
解决方案是使用 using
指令引用其他命名空间中的重载,如 here and here 所述。 Michael Nastenko 在评论中提到了这一点。
因此 using ::operator<<;
,其中 ::
指的是全局命名空间。
因此代码将变为:
#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;
}
使用带有 --std=c++14 的 gcc 版本 5.2.0 (GCC),如果命名空间 MyNamespace 中被注释掉的运算符 ostream 未被注释掉,则以下代码将不再编译。这是错误还是功能? (用 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;
}
我得到的操作符 << 未注释的错误消息是:
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;
^
如所述here, this is an example of name hiding。通过在命名空间 MyNamespace
中定义 operator<<
,来自更高命名空间(如全局)的所有定义都被隐藏。
请注意,如前所述here:
[...]this feature doesn't interfere with Koenig lookup [...], so IO operators from
std::
will still be found.
解决方案是使用 using
指令引用其他命名空间中的重载,如 here and here 所述。 Michael Nastenko 在评论中提到了这一点。
因此 using ::operator<<;
,其中 ::
指的是全局命名空间。
因此代码将变为:
#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;
}