2016-07-13 1 views
0

私はこれが畳み込まれているようですが、誰かが私の間違いを指摘してくれることを願っています。デザインがあなたの口の中に悪い味を残すと確信しています。私はデザインの選択肢を聞いてうれしいです。しかし、この形式は、問題領域のモデリングに由来します。テンプレート引数を解決できないために多型に失敗しましたか?

私はばかげていると確信していますが、テンプレートが継承して私を混乱させる方法については何かがあります。ここではいくつかは、以下の説明でコードをダウン切り詰めです:

// main.cpp 

#include <cstdio> 

template <typename POD> 
class A { 
public: 
    POD data; 
    POD get_a() { return data; } 
}; 

template <typename T> 
class B { 
public: 
    virtual void do_something_with_an_A_child(const T&) = 0; 
}; 

class ADerived : public A<float> { 
public: 
    ADerived(float a) { data = a; } 
}; 

class BDerived : public B<ADerived> { 
public: 
    virtual void do_something_with_an_A_child(const ADerived& someA) { 
    printf("A bit of A-type's data: %f\n", someA.data); 
    } 
}; 

template <typename POD> 
class Aggregator { 
public: 
    A<POD>* instanceOfA; 
    B<A<POD>>* instanceOfB; 
    Aggregator(A<POD>* anA, B<A<POD>>* aB) : instanceOfA(anA), instanceOfB(aB) {} 
}; 

int main() { 
    ADerived myADerived(3.14159f); 
    BDerived myBDerived; 

    Aggregator<float> myAggregator(&myADerived, &myBDerived); 

    return 1; 
} 

のでA署名ほんの一部がビルトインされるタイプ(複数可)のクラステンプレートです。 (私の特別なケースでは、Aにはその内部データを操作するメソッドがあります)。クラスBは、A<.>の特定のインスタンスを対象としたいくつかの操作に対するインタフェースを約束します。上のコードでは、ABをテンプレートクラスとして定義し、これらのテンプレートクラスを継承するクラスを作成して、ADerivedBDerivedとしています。

(真の場合、Aは、数学的モデルといくつかのデータを表し、そしてBモデルに数学的な最適化を行うためのインタフェースである。)次に

のインスタンスへのリンクを有していなければならないクラスをADerivdedBDerived(それらのインターフェイスに基づいて一般的なアルゴリズムを作成する目的で)私はAggregatorを呼び出しました。これは単にコンストラクタでいくつかのポインタが必要です。 は、PODタイプについて知りたいだけです。これは、インターフェイスを操作するだけであり、オブジェクトに含まれるものについてあまり心配する必要がないからです。

私は-std=c++14clang++から次のコンパイラエラーを取得する:

main.cpp:42:21: error: no matching constructor for initialization of 'Aggregator<float>' 
    Aggregator<float> myAggregator(&myADerived, &myBDerived); 
        ^   ~~~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:35:3: note: candidate constructor not viable: no known conversion from 'BDerived *' to 'B<A<float> > *' for 2nd argument 
    Aggregator(A<POD>* anA, B<A<POD>>* aB) : instanceOfA(anA), instanceOfB(aB) {} 
^

意味が明確であるが、私はそれがBDerivedB<A<float>>であることを見ることができない理由はわかりません。つまり、具体的にはB<ADerived>ですが、ADerivedA<float>であるため、BDerivedB<A<float>>と見なされます。これは明らかにそうではありませんので、私は何かばかげたことをしています。誰かにそれを指摘させてもらうか、これはC++では不可能です。代替設計提案が必要です。

+1

'B 'と 'B >' ADerived'が 'か'から継承された場合に完全に異なるタイプが、それは問題ではないです。あなたのデザインは正しく見えませんが、何かを提案することは難しく、十分な情報がありません。 – Slava

+1

提案、テンプレートなしで特定のタイプに必要なものを実装して一般化することは非常に簡単です。 – Slava

+0

ありがとう@Slava。それを信じるかどうか、これは既に特定のタイプのためにコーディングしたアルゴリズムから_lift_しようとする試みです。私はライブラリ/フレームワークに私のAPIを一般化しようとしています。それは正しいことが難しく、私はそうではないと確信しています。しかし、私たちはみな何とか学びます。 – Timtro

答えて

2

テンプレート引数は、静的で正確な型に解決されます。したがって、ADerivedA<POD>の子孫であっても、B<ADerived>B<A<POD>>に減衰しません。使用B

  • Aggregatorで、もう一つのテンプレートパラメータ、Tを取り、必要に応じてTの公開A<POD>Tのベースであること、または
  • std::enable_if<>std::is_base<>を使用して)確保:あなたはこのことで回避するかもしれませんa typedefとし、AggregatorTとし、TA<B::T>Aggregatorに格納する。
+1

ありがとうございます。あなたは私が必要とする答えに私をインスパイアしました。派生したクラスの型をテンプレート引数として取り、 'auto'と' decltype(。) 'を使って、必要に応じて戻り値の型に関する情報を取得します。そうすれば、元の 'A'だけがPODタイプについて知る必要があります。 – Timtro

関連する問題