1

次のような訪問関数を備えたクラスがいくつかあります。

struct Person {
   std::string name;
   unsigned age;

  template<class Visitor>
  void visit(Visitor& c)
  {
      c("name", name);
      c("age", age);
  }

  template<class Visitor>
  void visit(Visitor& c) const
  {
      c("name", name);
      c("age", age);
  }
};

私には次のような訪問者がいます:

struct PrintVisitor
{
    PrintVisitor(std::ostream& stream)
        : m_stream(stream)
    {}

    template<class T>
    void operator()(const std::string& name, const T& v)
    {
        m_stream << name << ": " << v << std::endl;
    }

private:
    std::ostream& m_stream;
};

訪問者ごとに、ストリーム演算子を定義します。

std::ostream& operator<<(std::ostream& stream, const Person& p)
{
    PrintVisitor printer(stream);
    p.visit(printer);
    return stream;
}

訪問可能なクラスを受け入れる単一の演算子<<を提供することは可能ですか?

(現在、私は印刷を実験しているだけですが、実際にはjsonのシリアル化、逆シリアル化、そしておそらく等式および小なり演算子を実装したいと思っています。

アップデート

私はDavidsソリューションを使用しました:

CRTPの基本クラス:

template <class T>
struct Visitable {};

訪問可能なすべてのクラスはそこから継承します。

struct Person : Visitable<Person> { ... }

演算子と関数はそのようにテンプレート化されており、静的キャストを使用してクラスにアクセスします。

template<class T> 
std::ostream& operator<<(std::ostream& stream, const Visitable<T>& p) 
{ 
    PrintVisitor printer(stream); 
    static_cast<const T&>(p).visit(printer); 
    return stream; 
}
4

2 に答える 2

1

あなたが取っているアプローチは、ブーストシリアライゼーションライブラリの実装方法に似ていますがoperator&、ライブラリと対話するためにオーバーロード (バイナリであり、アドレスオブではありません) であるという違いがあります。次に、訪問者は型に対して単一のserialize操作を使用します。

さて、問題は私が質問を本当に理解していないということです:

テンプレート化された関数で一度だけ演算子を実装する必要がない可能性はありますか?

operator<<任意のビジター (シリアライザー) タイプを取るシングルを提供するということですか? それが問題であれば、あまり詳しく説明しなくても、継承と CRTP を使用してこれを解決することができます。具体的な訪問者を引数として受け取る、すべての訪問者のテンプレート化されたベースでメンバー関数として演算子を実装します。

それが比較演算子にどのように適用されるかはよくわかりませんが、シリアライゼーションでは自然operator<<operator>>見えますが、他の操作では驚くべきことです。

于 2012-08-14T13:32:38.677 に答える
0

このようなことをしたいということですか?

template<class Visitable>
std::ostream& operator<<(std::ostream& stream, const Visitable& v)
{
    PrintVisitor printer(stream);
    v.visit(printer);
    return stream;
}

これはもちろんあいまいさを引き起こします。あなたが欲しいのはこれです:

template<class Visitable implements visit>
std::ostream& operator<<(std::ostream& stream, const Visitable& v)
{
    PrintVisitor printer(stream);
    v.visit(printer);
    return stream;
}

これが可能かどうかはわかりません。

これを行うこともできます:

class Visitable { ... }
class Person : public Visitable { ... }

次に、通常の関数を実装します。

std::ostream& operator<<(std::ostream& stream, const Visitable& v)

ただし、仮想関数呼び出しのわずかなオーバーヘッドがあります。

于 2012-08-14T13:41:19.007 に答える