2010-05-12 73 views
3

以下示例編譯細,但我不能找出如何分離聲明和操作員< <()的定義是這樣的特定情況。如何在模板類中拆分模板友元函數的定義?

每次我嘗試拆分定義的朋友是造成麻煩和gcc抱怨運營商< <()定義必須採用一個參數。

#include <iostream> 
template <typename T> 
class Test { 
    public: 
     Test(const T& value) : value_(value) {} 

     template <typename STREAM> 
     friend STREAM& operator<<(STREAM& os, const Test<T>& rhs) { 
      os << rhs.value_; 
      return os; 
     } 
    private: 
     T value_; 
}; 

int main() { 
    std::cout << Test<int>(5) << std::endl; 
} 

操作< <()應該有不同類型的輸出流(標準::法院,的std :: wcout或升壓:: ASIO ::知識產權:: TCP的工作自由的第一個參數: :iostream的)。第二個參數應該綁定到周圍類的專用版本。

Test<int> x; 
some_other_class y; 

std::cout << x; // works 
boost::asio::ip::tcp::iostream << x; // works 

std::cout << y; // doesn't work 
boost::asio::ip::tcp::iostream << y; // works 

除此之外使用非成員函數不等同於分裂的定義和聲明,因爲非成員函數不能訪問私有屬性的類。

+0

可能的複製:http://stackoverflow.com/questions/476272/how-to-properly-overload-the-operator-for-an-ostream – Stephen 2010-05-12 15:07:09

+0

爲什麼你想參數化OSTREAM類型?常見的習慣用法是定義operator << as:'std :: ostream&operator <<(std :: ostream&os,Test &rhs){...}' – 2010-05-12 15:46:53

+0

@dribeas:因爲我希望能夠使用其他輸出流也是如此。像boost :: asio :: ip :: tcp :: iostream和boost :: asio :: local :: stream_protocol :: iostream。 – joke 2010-05-12 15:55:28

回答

4

最簡單的可能是讓所有這些模板運營商的朋友:

#include <iostream> 
template <typename T> 
class Test 
{ 
    public: 
     Test(const T& value) : value_(value) {} 

     template <typename STREAM, typename U> 
     friend STREAM& operator<<(STREAM& os, const Test<U>& rhs); 

    private: 
     T value_; 
}; 

template <typename STREAM, typename T> 
STREAM& operator<<(STREAM& os, const Test<T>& rhs) 
{ 
    os << rhs.value_; 
    return os; 
} 
+0

指定operator <<()作品的第二個模板參數。 – joke 2010-05-12 15:22:11

+0

我無法找到重用'T'的方法,即使是在函數定義之前有2個'template'聲明的典型模板成員函數。無障礙方面並不重要,但確實看起來很奇怪。 – 2010-05-12 16:12:29

1

難道不應該之類的外部定義?

template <typename T> 
class Test 
{ 
    ... 
    template <typename STREAM> 
    friend STREAM& operator<<(STREAM& os, const Test<T>& rhs); 
}; 

template <typename STREAM, typename T> 
STREAM& operator<<(STREAM& os, const Test<T>& rhs) 
{ 
    os << rhs.value_; 
    return os; 
} 
+0

你試過編譯過嗎? – 2010-05-12 15:08:54

+0

通常你會寫: 模板 模板 STREAM及測試 ::運算符<<(STREAM和OS,常量測試&右){ OS << rhs.value_; return os; }; 但在這種情況下不起作用。 – joke 2010-05-12 15:10:44

+0

即使它可以工作,該示例仍然會丟失: 測試 :: operator <<(...) – joke 2010-05-12 15:13:18

1

我可以達到最近的是

#include <iostream> 

template <typename T> 
class Test; 

template <typename STREAM, typename T> 
STREAM& operator<<(STREAM& os, const Test<T>& rhs); 

template <typename T> 
class Test { 
public: 
    Test(const T& value) : value_(value) {} 

    template <typename STREAM, typename U> 
    friend STREAM& operator<< (STREAM& os, const Test<U>& rhs); 

private: 
    T value_; 
}; 

template <typename STREAM, typename T> 
STREAM& operator<<(STREAM& os, const Test<T>& rhs) { 
    os << rhs.value_; 
    return os; 
} 

int main() { 
    std::cout << Test<int>(5) << std::endl; 
} 

它聲明的所有操作< <成爲朋友,而不是隻由T參數化的問題。問題是部分專門化功能是不可能的。人們會喜歡使用

template <typename STREAM> 
friend STREAM& operator<< <STREAM, T> (STREAM& os, const Test<T>& rhs); 

但這不是有效的語法。 (當然,和部分特化不能申報的朋友)

+0

你說得對,它與原作不一樣。但是由於原始版本可以在類定義中定義,因此應該有一種拆分聲明和定義的方法。 – joke 2010-05-12 15:30:32

+0

原始函數首先定義了一個帶有一個模板參數的函數。如果你想要一些相同的東西,你必須爲每個類型T定義一個函數。這是可能的,但可能很痛苦。 – AProgrammer 2010-05-12 15:42:44

+0

是的,只要環境模板類被實例化,聲明/定義就是具有一個模板參數的模板成員函數。 – joke 2010-05-12 15:51:26

0

的問題是,在你目前的朋友的代碼僅在第一個參數類型參數化一個模板函數。也就是說,對於類模板的每個實例化類型T(稱之爲mytype),你宣佈一個免費的模板功能:

template <typename STREAM> 
STREAM& operator<<(STREAM& os, Test<mytype> const & x); 

重要的一點還有就是Test<mytype>Test與類型參數mytype特定例。

如果您確實想聲明一個朋友函數,該函數在Test模板的流類型和實例化類型中均被模板化,則必須聲明具有兩個參數的朋友。另一方面,我建議您不要在流類型上設置參數operator<<,並且同時在類大括號中定義它,因爲它具有輕微的優點(名稱查找規則略有不同)。

+0

@dribeas:http://stackoverflow.com/questions/2819994/2820743#2820743 – joke 2010-05-12 16:23:13

0

對於Test類的每個實例化類型T,模板函數操作符< <()被公開,它可以在不同種類的流上操作。運算符< <()函數有一個空閒的第一個參數,但是有一個固定的第二個參數。

例如:

Test<int> x; 
some_other_class y; 

std::cout << x; // works 
boost::asio::ip::tcp::iostream << x; // works 

std::cout << y; // doesn't work 
boost::asio::ip::tcp::iostream << y; // works 

這是測試類應該在上班的路上。

+0

不要'boost :: asio :: ip :: tcp :: iostream'和'boost :: asio :: ip :: tcp :: iostream從繼承自std :: basic_ostream的std :: basic_iostream繼承 – 2010-05-12 17:03:26

+0

我不認爲他們繼承。他們應該是模板專業化。 boost :: asio :: ip :: tcp :: iostream應該是模板basic_socket_iostream的專門化。 – joke 2010-05-12 17:16:38

+0

只需按照代碼...(boost/asio/basic_socket_iostream.hpp:'template <...> class basic_socket_iostream:public boost :: base_from_member <...>,public std :: basic_iostream ')。這很有意義,總的來說,你不需要重寫任何'operator <<'來使用asio iostreams。如果你可以寫入'cout',那麼你可以寫入一個tcp流。 – 2010-05-12 17:20:58