假设以下代码。 MyStream类有模板重载运算符<<。还有全球超载的运营商MyStream&运算符<< (MyStream&,const MyClass&)。令人困惑的是(通过编译器)为两个几乎相同的情况生成不同的方法(参见main()函数的主体)。我认为应该在两种情况下使用全局运算符,但事实并非如此。为什么这样?
#include <iostream>
class MyStream;
class MyClass;
MyStream& operator << (MyStream& stream, const MyClass&);
class MyStream
{
public:
template <typename T>
MyStream& operator << (const T&)
{
std::cout << __FUNCTION__ << " " << typeid(T).name() << std::endl;
return *this;
}
};
class MyClass
{
};
MyStream& operator << (MyStream& stream, const MyClass&)
{
std::cout << __FUNCTION__ << " " << typeid(MyClass).name() << std::endl;
return stream;
}
int main(int, char**)
{
// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();
std::cout << std::endl;
// 2. Template instantiation
MyStream() << MyClass();
std::cin.get();
return 0;
}
使用Microsift Visual C ++编译器9.0(x86)编译的程序输出:
MyStream::operator << int
operator << class MyClass
MyStream::operator << class MyClass
答案 0 :(得分:5)
// 2. Template instantiation
MyStream() << MyClass();
在这种情况下,表达式MyStream()
创建一个临时对象( rvalue ),它不能绑定到非const引用,因此编译器会选择成员函数模板,因为在为了调用自由函数,临时对象必须作为函数的第一个参数传递,这在这里是不可能的,因为自由函数的第一个参数的类型是非const引用。所以MyStream << MyClass()
调用成员函数。
但是当你这样写:
// 1. Used globally defined operator for MyClass
MyStream() << int() << MyClass();
它首先调用传递int()
的成员函数,并且成员函数返回一个类型为MyStream&
的对象,现在可以作为第一个参数传递给自由函数(因为它是否< / strong>更多 rvalue ,它现在是 lvalue ),然后它调用free函数,传递类型MyStream&
的对象作为第一个参数并{{ 1}}作为第二个参数。
这很有意思,类似的事情发生在这里: