2012-02-18 32 views
3

假設下面的代碼。有一流的MyStream女巫模板重載運營商< <。還有全局重載的運營商MyStream &運營商< <(MyStream &,常量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(86)編譯:

MyStream::operator << int 
operator << class MyClass 

MyStream::operator << class MyClass 
+1

有趣的問題!短代碼和乾淨的問題陳述。我希望這裏的所有問題都和這一個一樣清楚! – Sjoerd 2012-02-18 14:03:31

回答

5
// 2. Template instantiation 
MyStream() << MyClass(); 

在這種情況下,表達式MyStream()創建臨時對象(右值),其不能被綁定到非const引用,所以編譯器選擇成員函數模板,因爲爲了調用自由函數,臨時對象必須作爲第一個參數傳遞給函數,這在這裏是不可能的,因爲t自由函數的第一個參數的類型是非常量引用。所以MyStream << MyClass()調用成員函數。

但是,當你這樣寫:

// 1. Used globally defined operator for MyClass 
MyStream() << int() << MyClass(); 

它首先調用成員函數傳遞int()和成員函數返回MyStream&類型的對象現在可以傳遞給免費功能的第一個參數(因爲它是沒有多個右值,現在一個左值是),那麼它將調用自由函數,傳遞MyStream&類型的對象作爲第一個參數,如MyClass()第二個參數。

這是有趣的,和類似的事情發生在這裏:

+1

我明白了。感謝澄清。 – tim 2012-02-18 13:40:44