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 <<の非メンバーおよび非フレンド関数に変換する私の試みの1つです。

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

元のクラスは問題ありません。operator <<ストリームへの書き込み用が必要な場合は、メンバー以外の非フレンド関数にする必要があることは事実ですが、関数がパブリックメンバー関数を呼び出せない理由はありません。仕事。

于 2013-02-20T16:19:39.033 に答える
1

あなたはあなたの質問をかなり明確にしたので、私の最初の答えはもはや当てはまりません.

更新された回答: MyClass テンプレート内で typedefed されている型のみを受け入れるようにテンプレートを制約したいと考えています。このような制約は通常、SFINAE の適用によって、特にstd::enable_if(またはboost::enable_if、ライブラリに C++11 サポートのその部分がない場合は) によって実現されます。悲しいことに、is_typedeffed_insideあなたの場合に使用できる a のような特性はありません。さらに悪いことに、単純な typedef を使用してそのようなトレイトを記述する方法はありません。指定されたクラス内で型定義されることについて特別なことは何もないためです。 type には、どこかにエイリアス名があります。

しかし、あなたの typedef が質問で示したものだけである場合は、良いニュースがあります。operator<<そのためには、正確に 2 つ必要です。

  1. の 1 つは、任意のMyClass インスタンス化boost::dynamic_bitset<>の BoolTable であるためです。
  2. std::vector<T>対応する各 の MsgTable であるため、 用にテンプレート化された別のものMyClass<T>

欠点は、このテンプレート化された を使用すると、MyClass の使用とはまったく関係なくても、operator<<任意の を出力できることです。しかし、それは適切な の他の可能な実装にも当てはまります- MSG パラメータに明示的な制限がない場合、 FooBar が実行可能なものを作ることに制限はありません。std::vector<FooBar>FooBaroperator<<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); 
}
于 2013-02-20T14:53:41.353 に答える
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 に答える