2013-02-20 185 views
2

我想使用模板類的嵌套類型實現模板函數。使用模板類的嵌套類型作爲模板參數

我剛剛讀了here,最好是將operator <<作爲非會員和非朋友功能。因此,我決定搬到外面MyClass功能toStream()tableToStream()

template <typename T> 
class MyClass 
{ 
public: 
    typedef boost::dynamic_bitset<> BoolTable; 
    typedef std::vector<T>   MsgTable; 
private: 
    BoolTable b_; 
    MsgTable m_; 
public: 
    const BoolTable& getB() const { return b_; } 
    const MsgTable & getM() const { return m_; } 

    std::ostream& toStream (std::ostream& os) const 
    { 
    os <<"Bool: "; tableToStream (os, getB()); os <<'\n'; 
    os <<"Msg:"; tableToStream (os, getM()); os <<'\n'; 
    return os; 
    } 

    template <typename TABLE> 
    std::ostream& tableToStream (std::ostream& os, const TABLE& table) const 
    { 
    for (int i=0; i < table.size(); ++i) 
     os << table[i] <<','; 
    return os; 
    } 
}; 

template <typename T> 
std::ostream& operator << (std::ostream& os, const MyClass<T> mc) 
{ 
    return mc.toStream(os); 
} 

這很容易MyClass::toStream()轉換爲operator <<非會員和非友元函數:

template <typename T> 
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc) 
{ 
    os <<"Bool: "; mc.tableToStream (os, mc.getB()); os <<'\n'; 
    os <<"Msg:"; mc.tableToStream (os, mc.getM()); os <<'\n'; 
    return os; 
} 

但我想用完全operator <<而不是致電MyClass::tableToStream()

template <typename T> 
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc) 
{ 
    os <<"Bool: "<< mc.getB() <<'\n'; 
    os <<"Msg:" << mc.getM() <<'\n'; 
    return os; 
} 

對於功能MyClass::tableToStream()我可以使用以下實現,但這可能會混淆流輸出,因爲該函數過於通用(任何類型都可能是TABLE)。

template <typename TABLE> 
std::ostream& operator << (std::ostream& os, const TABLE& table) 
{ 
    for (int i=0; i < table.size(); ++i) 
    os << table[i] <<','; 
    return os; 
} 

因此,我想限制到嵌套類型的MyClass。下面是我嘗試MyClass::tableToStream()轉換成標準operator <<非成員和非友元函數的一個:

template <typename T, typename MyClass<T>::TABLE> 
std::ostream& operator << (std::ostream& os, const TABLE& table) 
{ 
    for (int i=0; i < table.size(); ++i) 
    os << table[i] <<','; 
    return os; 
} 

但誤差約爲typename MyClass<T>::TABLE

+0

是否流(OS)需要一個模板參數?它通常只是std :: ostream。 – 2013-02-20 14:50:30

+0

你原來的'toStream()'不會引用'MyClass'中的任何內容,甚至不會引用'MsgTable'。目前還不清楚你想要達到的目標。你確定'TABLE'應該是'toStream()'的模板參數嗎? – Angew 2013-02-20 14:58:08

+0

@VaughnCato,OS也可以是std :: ofstream或任何其他輸出流。請參閱後http://stackoverflow.com/questions/236801/should-operator-be-implemented-as-a-friend-or-as-a-member-function/237111#237111乾杯;-) – olibre 2013-02-20 15:22:59

回答

1

既然你已經澄清你的問題很多,我的第一個回答不適用任何更多的,我會刪除編輯它給你的東西,可能更適合:

更新答案: 你想限制模板只接受MyClass模板中的typedeff類型。這種限制通常通過應用SFINAE來實現,特別是通過std::enable_if(或boost::enable_if,如果您的程序庫缺少C++ 11支持的那部分)來實現。可悲的是,沒有像is_typedeffed_inside這樣的特質可以用於你的案例。更糟糕的是:沒有辦法用簡單的typedef來編寫這樣的特性,因爲在給定的類中沒有特別的typedeff - 編譯器無法確定(並且不感興趣)如果給定已知type在某處有一些別名。

但是,如果你的typedef只是你在你的問題顯示的,我對你有個好消息:你需要整整兩個operator<<爲:

  1. 一個用於boost::dynamic_bitset<>,因爲這是BoolTable爲任何 MyClass實例化。
  2. 另一個模板爲std::vector<T>,因爲這是每個對應的MyClass<T>的MsgTable。

的缺點是,與此模板operator<<,你能夠輸出任何std::vector<FooBar>,即使FooBar是完全無關的任何用途的MyClass。但這適用於任何其他可能的實施operator<<的 - 如果沒有對MSG參數進行明確的限制,那麼對於使成爲可行的MyClass<MSG>::MsgTable的FooBar沒有限制。

我的結論爲你的問題:你想有operator<<爲方便看起來,因爲它通常用於這個目的。在你的情況下,你可以爲MyClass<MSG>對象提供它,但是對於單獨的內部typedef,沒有辦法這樣做。

我想實現這樣的說法:

template <class MSG> 
class MyClass { 
    /* ... */ 
public: 
    // instead of declaring op<< a friend, redirect to a method that has 
    // natural access to private members 
    std::ostream& printToStream(std::ostream& os) const 
    { 
    os << "Bool: "; 
    tableToStream (getB(), os); 
    os <<"\nMsg:"; 
    tableToStream (getM(), os); 
    return os <<'\n'; 
    } 
private: 
    // make this one private so nobody can misuse it to print unrelated stuff 
    template <class Table> 
    static void tableToStream(Table const& table, std::ostream& os) 
    { 
    std::copy(begin(table), end(table), ostream_iterator(os, ", "));  
    } 
}; 

template <typename MSG> 
std::ostream& operator << (std::ostream& os, const MyClass<MSG>& mc) 
{ 
    return mc.printToStream(os); 
} 
+0

是的,我希望'operator <<'只使用公共類型的'MyClass'。恐怕你的示例的'operator <<'接受任何其他類,並可能會混淆我項目的流輸出。但我想知道非常方便的解決方案。如果這個解決方案太不可靠了,那麼我會回滾我的修改......乾杯;-) – olibre 2013-02-20 15:42:05

-1

我相信你很困惑。 typename只是爲了能夠將它與其他模板參數分離。嘗試將其重命名爲

template <typename OS, typename MSG, typename MSGTable> 
OS& operator << (OS& os, const MSGTable& table) const{} 

然後將其用作對象。

請參閱here

+0

-1:在你的例子中什麼是TABLE,當不能推導出MSG和MSGTable時,如何將操作符函數與操作符語法結合使用? – Angew 2013-02-20 14:59:19

+0

做了一些更正,除了我剛剛複製函數的簽名。 – 2013-02-20 15:00:37

+0

Hi @ bash.d謝謝,但我知道如何編寫基本的模板函數。在你的例子的'operator <<'中,不使用'typename MSG'。而且,修飾符'const'只能用於非靜態成員函數,而不是在這種情況下。乾杯;-) – olibre 2013-02-20 16:15:37

1

你原來的班是好的。確實,如果你想有一個operator <<寫入一個流,它應該是一個非成員的非朋友函數,就像你有,但沒有理由,該函數不能調用一個公共成員函數做工作。

+0

但是我的成員函數'tableToStream'沒有使用其他私有成員。因此'tableToStream'可以移出'MyClass'之外。事實上,我意識到我的問題並不清楚:我想知道如何使用模板類的**嵌套類型**作爲模板參數。我更新了我的問題(我可以給出更基本的源代碼...)。乾杯;-) – olibre 2013-02-20 16:51:42

+0

嗨,@ArneMertz向我解釋說,使用**嵌套類型的'typename'的想法不起作用。因此,我的解決方案是按照您的建議將'tableToStream()'保存在'MyClass'中。謝謝;-) – olibre 2013-02-22 15:53:45

0

我終於找到this similar question

在我的情況下解決方案是:

template <typename T> 
std::ostream& operator << (std::ostream& os, 
          typename MyClass<T>::TABLE const& table) 
{ 
    for (int i=0; i < table.size(); ++i) 
    os << table[i] <<','; 
    return os; 
} 

UPDATE:作爲@ArneMertz指出,上述功能不起作用。
下面是完整的代碼我已經測試:

#include <ostream> 
#include <boost/dynamic_bitset.hpp> 

template <typename T> 
class MyClass 
{ 
    public: 
    typedef boost::dynamic_bitset<> BoolTable; 
    typedef std::vector<T>   MsgTable; 

    BoolTable b_; 
    MsgTable m_; 

    const BoolTable& getB() const { return b_; } 
    const MsgTable & getM() const { return m_; } 
}; 

template <typename T> 
std::ostream& operator << (std::ostream& os, 
          typename MyClass<T>::TABLE const& table) 
{ 
    for (int i=0; i < table.size(); ++i) 
    os << table[i] <<','; 
    return os; 
} 

template <typename T> 
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc) 
{ 
    os <<"Bool: "<< mc.getB() <<'\n'; // <-- this line is OK because it 
    os <<"Msg: "<< mc.getM() <<'\n';   //uses boost operator<< 
    return os; 
} 

main功能:

#include <iostream> 

int main() 
{ 
    MyClass<int> var; 
    var.b_.push_back(true); 
    var.b_.push_back(false); 
    var.b_.push_back(true); 
    var.m_.push_back(23); 
    var.m_.push_back(24); 
    var.m_.push_back(25); 

    std::cout << var; 
} 
+1

這不適用於此,因爲MyClass 沒有名爲'TABLE'的成員類型 - 至少不像您在問題的示例代碼中描述的那樣。您必須指定「MyClass :: BoolTable」或「MyClass :: MsgTable」 - 但您無法同時在兩個模板中工作。 – 2013-02-21 08:20:02

+0

嗨@ArneMertz。我同意'TABLE'不是現有類型的'MyClass '。但在上面的函數中,我使用'TABLE'作爲'typename',因此它可以是任何類型的'MyClass '。因此,MyClass :: TABLE可以是MyClass :: BoolTable或MyClass :: MsgTable。請嘗試編譯代碼,你會看到它的作品。我正在更新我的答案,爲您提供完整的測試代碼。感謝您的幫助。玩得開心,乾杯;-) – olibre 2013-02-22 15:14:06

+0

我的歉意@ArneMertz,你是100%的權利。當我昨天測試它時,我認爲它是可以的,但它使用來自boost的'operator <<'...非常感謝您的相關評論;-)。因此,我的解決方案是將'tableToStream()'保存在'MyClass'中。再見 ;-) – olibre 2013-02-22 15:51:20