私はアプリケーションの設計を開発しており、ある種のVisitor デザイン パターンを適用できると思っていましたが、それはまさに私が探しているものではないことが判明しました。この場合、誰かが私が必要とするバリアントを教えてくれるでしょうか?
私のコードの多くには、次のようなテンプレート引数「ContainerType」があります
template <class ContainerType>
class MyClass
{
public:
void doSomething(ContainerType& container) { ... }
};
現在、通常は多くのデータ フィールドを共有する「コンテナ」の数は少ないですが増え続けています。
template<class ContainedType>
struct ContainerBase
{
ContainedType data;
};
struct Container1: ContainerBase<A>, ContainerBase<B>
{};
struct Container2: ContainerBase<A>, ContainerBase<C>
{};
Container1 と Container2 は、MyClass (およびその他) のテンプレート引数として使用されるようになりました。ここで、A、B、C はいくつかの定義済みクラスです。(get<A>(container)含まれているデータにアクセスするなどの方法があります。この設計により、必要な型を含むすべてのコンテナー型で MyClass を使用できるというコンパイル時の安全性が提供されます。)
ここで、「コンテナに特定のタイプ (例: A) が含まれている場合は何かを実行し、それ以外の場合は何もしない」という機能を追加したいと考えています。
これは、訪問者のように見えるもので行うことができます (ただし、仮想メソッドは使用されないことに注意してください)。「コンテナに A が含まれている場合はこれを行い、D が含まれている場合は別のことを行い、そうでない場合は何もしない」こともできます。これは
template <class ContainerType>
class MyClass
{
public:
void doSomething(ContainerType& container)
{
container.accept(*this);
}
void visit(B& b){...}
void visit(D& d){...}
template<typename T>
void visit(T& t){}
};
struct Container1: ContainerBase<A>, ContainerBase<B>
{
template<class T>
void accept(T& t)
{
t.visit(ContainerBase<A>::data);
t.visit(ContainerBase<B>::data);
}
};
これは私が望んでいたことですが、ここに示す実装では、すべての ContainerType に対して受け入れを実装する必要があるため、より良い方法を探しています。誰かがacceptメソッドから派生しContainer1たContainerBase<D>のに展開するのを忘れた場合、事態は悪化します。さらに悪いことに、const バージョンと非 const バージョンの accept が必要になり、一部のコンテナーには 5 つ以上の型が含まれているため、見た目も良くありません。
すべてのコンテナ クラスは複数回の継承によって構築されているContainerBase<T>ため、この構造を使用して、ContainerBase クラスに accept (および accept(..) const) を実装できないか考えてみました。私はすでに Lokis のタイプリストを見てきましたが、ここでそれらを使用する方法がわかりません。何か考えはありますか?
それとも、訪問者のような構造なしでこれを行うことは可能ですか?
どうもありがとう!
編集:RTTIを使用できることはわかっていますが、可能であればランタイムチェックと仮想メソッドを避けたいです。