簡體   English   中英

使用模板類的嵌套類型作為模板參數

[英]using nested-types of a template-class as template parameter

我想使用模板類的嵌套類型來實現模板功能。

我剛剛在這里讀到,最好將operator <<實現為非成員和非朋友函數。 因此,我決定將函數toStream() 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

既然您已經澄清了很多問題,那么我的第一個答案將不再適用,我將對其進行刪除-編輯,以便為您提供更好的選擇:

更新的答案:您希望將模板限制為僅接受在MyClass模板中鍵入有效的類型。 通常通過應用SFINAE來實現這種約束,特別是通過std::enable_if (或boost::enable_if ,如果您的庫缺少C ++ 11支持的部分)。 可悲的是,沒有像is_typedeffed_inside這樣的特征可以用於您的案例。 更糟糕的是:僅使用普通的typedef就無法編寫這樣的特征,因為在給定的類中進行類型化沒有什么特別的-編譯器無法確定(並且不關心)給定的已知值類型在某處具有一些別名。

但是,如果您的typedef只是您在問題中顯示的typedef,那么我對您來說是個好消息:您恰好需要兩個operator<<

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

缺點是,使用此模板化的operator<< ,即使FooBar與MyClass的使用完全無關,您也可以輸出任何std::vector<FooBar> 但這適用於適當的operator<<的任何其他可能的實現-如果對MSG參數沒有明確限制,則對FooBar也沒有限制,使std::vector<FooBar>成為可行的MyClass<MSG>::MsgTable

我對您的問題的結論是:您希望使用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); 
}

你原來的課沒問題。 的確,如果您想要一個operator <<來寫入流,則它應該像您一樣是非成員非朋友函數,但是沒有理由該函數不能調用公共成員函數做工作。

我終於找到了類似的問題

就我而言, 解決方案是:

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;
}

更新:正如@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;
}

我相信您會感到困惑。 類型名稱只是為了能夠將其與其他模板參數分開。 嘗試將其重命名為

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

然后像一個對象一樣使用它。

這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM