2014-03-19 66 views
2

我想測試像下面這樣一個簡單的事情:的boost ::變種和運營商<<重載

#include <iostream> 
#include <boost/variant.hpp> 

template<typename T1,typename T2> 
std::ostream& operator<<(std::ostream& os, const std::pair<T1,T2>& dt){ 
    os << dt.first << dt.second; 
    return os; 
} 



int main(){ 

    boost::variant<int, std::pair<int,int>, bool> v; 
    v = std::pair<int,int>(3,3); 
    std::cout << v << std::endl; 

} 

這實際上應該工作,因爲正常的類型,如int, double等等,它編譯。 boost::variant有一個打印機vistor,它在內部用來輸出內容到流中。 其實這編譯失敗,但我真的不知道的問題:

的代碼失敗在這裏:在variant_io.hpp

template <typename OStream> 
class printer 
    : public boost::static_visitor<> 
{ 
private: // representation 

    OStream& out_; 

public: // structors 

    explicit printer(OStream& out) 
     : out_(out) 
    { 
    } 

public: // visitor interface 

    template <typename T> 
    void operator()(const T& operand) const 
    { 
     out_ << operand; // HEEEEEEERRRRREE!!!!!!!!!!!! 
    } 

private: 
    printer& operator=(const printer&); 

}; 

隨着消息:

/usr/local/include/boost/variant/detail/variant_io.hpp|64|error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&' 

有人知道我做錯了什麼,爲什麼?

非常感謝!

+0

這不是我們需要知道的能夠診斷問題的地方。當模板定義出現問題時,編譯器會打印一個擴展鏈。我們需要完整的輸出來告訴你發生了什麼。 –

+0

由於錯誤消息似乎來自MSC++,因此我會提到您需要從Visual Studio的「輸出」選項卡中獲取消息,「錯誤」窗口中會過濾掉註釋,並且對於此目的沒有用處。筆記緊跟在錯誤消息之後。 –

+0

想......想......想......答案其實很簡單。儘管這不是馬虎的問題的藉口,每當詢問編譯問題時,_complete_編譯器輸出都是_mandatory_。 –

回答

5

最有可能的是它找不到operator <<的超載,然後混淆試圖匹配其他超載,導致您收到的任何消息。

你做錯了什麼:你在全局命名空間中重載了流操作符,而不是在右側類中定義的命名空間,所以ADL沒有找到它。

不幸的是,試圖爲一個標準類重載流操作符是一個註定的練習。你不能這樣做。我不確定是否有明確的規定。但是,如果您將運算符放在命名空間std中,以便使它可以通過ADL正確找到,則違反了無法將自己的東西添加到名稱空間std的規則,除非是非常特殊的情況,這不是一個其中。

底線是std::pair沒有流操作符,也不可能合法添加一個有用的通用操作符。如果其中一個參數是您自己定義的類,則可以爲特定實例添加一個;在這種情況下,操作員需要放置在自己的班級旁邊。

+0

有一條規則說,除了重載_user定義的types_的符號之外,不得在「std」命名空間中放置任何東西。 –

3

重載operator<<必須通過參數相關查找找到。這意味着你必須把它放在其中一個參數的關聯名字空間中。

第一個參數只有一個關聯的名稱空間std。第二個也只有一個相關的命名空間,std。但是,只允許在std中爲用戶定義的類型過載符號。由於std::pair<int, int>而不是用戶定義類型,這是不允許的。但它允許您自己定義的結構或類。很顯然,在這種情況下,將重載放置到名稱空間更容易,而不是std

這就是說如果你把那個過載放在命名空間std中,那麼就會實際上工作。

另外請注意,boost::tuple確實有operator<<(在單獨的頭文件中,您必須包括,但它確實),所以您可以使用它。