为何在命名空间类中使用date.h的operator<<输出system_clock会编译失败?
为什么在命名空间内定义operator<<时,无法调用date库的time_point输出运算符?
问题复现代码
#include <iostream> #include <chrono> #include "date.h" namespace NS { class C {}; std::ostream &operator<<(std::ostream &o, const C &di) { using namespace date; using namespace std::chrono; std::cout << ::std::chrono::system_clock::now(); return o; } }
编译错误:
<source>:8250:19: error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'std::chrono::system_clock::time_point' (aka 'time_point<std::chrono::system_clock, duration<long, ratio<1, 1000000000>>>')) std::cout << ::std::chrono::system_clock::now();
注:如果将类和运算符移出命名空间,或者将运算符函数改名为SomeMethod,代码可正常编译。
问题原因
这是C++名称查找与参数依赖查找(ADL)交互的特殊情况:
- 当你在
NS命名空间中定义了operator<<(std::ostream&, const C&)后,在该函数内部调用<<运算符时,普通名称查找会优先找到NS内的这个operator<<——即使它的参数和当前调用不匹配,也会被纳入候选集。 date库的time_point输出运算符定义在date命名空间中,而ADL只会查找与参数类型直接关联的命名空间(这里是std(对应std::ostream)和std::chrono(对应time_point)),不会自动找到date命名空间的重载。- 虽然你用
using namespace date;将date的名称引入了函数作用域,但由于当前函数本身就是operator<<,编译器在重载决议时,会被NS内的非模板operator<<干扰,无法正确匹配date的模板operator<<。
而当你移除命名空间包裹,或者将函数改为非运算符函数时,普通名称查找不会优先找到不匹配的operator<<,因此能正确解析date库的重载。
解决方法
方法1:显式引入date的operator<<
在函数内部用using date::operator<<;代替using namespace date;,直接将date的输出运算符引入当前作用域:
std::ostream &operator<<(std::ostream &o, const C &di) { using date::operator<<; using namespace std::chrono; std::cout << ::std::chrono::system_clock::now(); return o; }
方法2:显式调用date的operator<<
直接指定命名空间调用,避免名称查找歧义:
std::ostream &operator<<(std::ostream &o, const C &di) { using namespace date; using namespace std::chrono; date::operator<<(std::cout, ::std::chrono::system_clock::now()); return o; }
方法3:将using namespace date;移到命名空间级别
把using namespace date;放在NS命名空间内部,让date的运算符在整个NS命名空间内可见:
namespace NS { using namespace date; class C {}; std::ostream &operator<<(std::ostream &o, const C &di) { using namespace std::chrono; std::cout << ::std::chrono::system_clock::now(); return o; } }
内容的提问来源于stack exchange,提问作者Spongman
相关产品推荐
相关产品推荐

