为什么实例化流操作符模板而不是全局重载操作符?

时间:2012-02-18 13:17:56

标签: c++ operator-overloading

假设以下代码。 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

1 个答案:

答案 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}}作为第二个参数。

这很有意思,类似的事情发生在这里: