2

我想使用模板类的嵌套类型来实现模板函数。

我刚刚在这里读到,最好实现operator <<为非会员和非朋友功能。因此,我决定将功能toStream()tableToStream()外部移动MyClass

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.

4

4 回答 4

1

由于您已经多次澄清了您的问题,因此我的第一个答案不再适用,我将删除-编辑它以提供可能更适合您的内容:

更新的答案: 您希望将模板限制为仅接受在 MyClass 模板中类型化的类型。这种约束通常是通过应用 SFINAE 来实现的,尤其是通过std::enable_if(或者boost::enable_if,如果您的库缺少 C++11 支持的那部分)。可悲的是,没有像 ais_typedeffed_inside这样的特征可以用于您的案例。更糟糕的是:没有办法仅使用普通的 typedef 来编写这样的 trait,因为在给定的类中进行类型定义并没有什么特别之处 - 编译器无法确定(并且不感兴趣)给定的已知type 在某处有一些别名。

但是,如果您的 typedef 只是您在问题中显示的那些,我有个好消息要告诉您:您需要两个operator<<

  1. 一个用于boost::dynamic_bitset<>,因为那是任何MyClass 实例化的 BoolTable。
  2. 另一个模板化的 for std::vector<T>,因为那是每个对应的 MsgTable MyClass<T>

缺点是,有了这个 templated operator<<,你就可以输出 any std::vector<FooBar>,即使FooBar与 MyClass 的任何使用完全无关。但这适用于正确operator<<'s 的任何其他可能实现 - 如果对 MSG 参数没有明确限制,则对 FooBar 没有限制使std::vector<FooBar>a 可行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); 
}
于 2013-02-20T14:53:41.353 回答
1

你原来的课程很好。确实,如果您想要operator <<写入流,它应该是一个非成员非朋友函数,就像您拥有的那样,但是没有理由函数不能调用公共成员函数来执行工作。

于 2013-02-20T16:19:39.033 回答
0

我终于找到了这个类似的问题

就我而言,解决方案是:

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;
}
于 2013-02-20T17:18:24.930 回答
-1

我相信你在混淆一些东西。类型名只是为了能够将它与其他模板参数分开。尝试将其重命名为

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

然后像对象一样使用它。

这里

于 2013-02-20T14:51:19.003 回答