据我了解,重载运算符由编译器转换为方法调用,例如:
stream << "test";
与:
stream.operator<<("test");
如果确实如此,那为什么会导致编译错误:
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::ostream s {std::cout.rdbuf()};
auto t = std::time(nullptr);
auto tm = *std::localtime(&t);
s.operator<<(std::put_time(&tm, "%H:%M:%S"));//doesn't work
return 0;
}
将doesn't work
行更改为:
s << std::put_time(&tm, "%H:%M:%S");
使代码编译。
C ++ 14上的GCC和MSVC 2017似乎都产生错误。这是编译器错误还是这两个语句不相等?
答案 0 :(得分:2)
这是您的代码,但已减少:
struct X { friend void operator+(X, X); };
int main() {
X var;
var + var; // ok
var.operator+(var); // fail
}
问题是,通过显式调用operator<<
,您所依赖的事实是它确实是类的运算符(如T& T::operator<<(const U&);
),而不是在类外部定义的运算符(因为如果操作员不是成员,则不能写var.operator<<(/*...*/)
)。
如果您编写var << something
,则除了在类中定义的运算符之外,查找(称为ADL)还将查找在类外部定义的运算符。
可以在类之外定义运算符,因为std::put_time
的返回类型指定为([ext.manip]:
未指定类型的对象,例如,如果
out
是类型basic_ostream<charT, traits>
的对象,则表达式out << put_time(tmb, fmt)
的行为就像调用了f(out, tmb, fmt)
一样,其中函数{{ 1}}定义为:[...]
由于要求的格式为f
,因此没有任何东西禁止标准库的实现在类外定义它,以便可以使用ADL找到它。