2016-09-10 7 views
3

のは、私は、基本クラスfooと2つの派生クラスABがあるとしましょう。私はその後、データメンバを持つ別のクラスbarを、持っているx、ことのいずれかA、または、しかし型は、他のデータメンバーx_typey_typeに依存し、z_type、およびそれらの値は、コンパイル時に利用できないことができyz、 。私はテンプレートのデータメンバを使用し、型の値を取得するコンストラクタで型を定義していますが、明らかに少なくともC++ 11では可能ではありません。だからどのように進める?クラスデータメンバタイプは別のデータメンバに基づいていますか?

class foo{ 
public: 
    foo(double); 
    int x_type; 
    virtual double do_something(double, int) = 0; 
}; 

class A: public foo { 
public: 
    A(double, double); 
    double do_something(double, int); 

private: 
    double z1; 
    double z2; 
}; 

class B: public foo { 
public: 
    B(double); 
    double do_something(double, int); 

private: 
    double w; 
}; 

class bar { 
public: 
    bar(); 
    double do_something2(int); 

private: 
    int x_type; 
    int y_type; 
    int x_type; 
    x; // these are either A or B... 
    y; 
    z; 
}; 

そしてコンストラクタで、私は、未知のタイプの派生クラスとデータメンバのはるかに高い数に制限はありません私の実際のアプリケーションでは

if(x_type == 1){ 
    x = A(arg1, arg2); 
} else { 
    x = B(arg3); 
} 

のようなものを持っているでしょう。 bar複数のテンプレートパラメータを持つテンプレートクラスを作成することが可能かどうか疑問に思っていましたが、パラメータタイプが別のパラメータに依存するかどうかわかりません。

+0

を次のようにismisを定義するには、以下の構造体struct indexSeqstruct indexSeqHelperを実装することができます整数値を使用して型を列挙することは、Evil™の反パターンです。おそらくこれは、多型クラス 'foo'へのポインタを持つデザインに対応しています。仮想デストラクタを持つ必要があります。 –

答えて

2

あなたがポリモーフィズムを使用し、共通の基底クラスはFooを利用する必要があります。

private: 
    int x_type; 
    int y_type; 
    int x_type; 
    std::unique_ptr<Foo> x; // these are either A or B... 
    std::unique_ptr<Foo> y; 
    std::unique_ptr<Foo> z; 

}; 

次に、あなたのコンストラクタでは、正しいタイプからXYZを作成することができます。

if(x_type == 1){ 
    x.reset(new A(arg1, arg2)); 
} else { 
    x.reset(new B(arg3)); 
} 

それは良いです意思決定のロジックと構造の詳細(時にはかなり複雑かもしれません)を隠すために、いわゆる「ファクトリ」クラスまたは関数で正しいFooインスタンスを作成するコードを移動するよう練習します。

1

すべての変数の静的な型はコンパイル時に知られなければならないので、実行時オブジェクトの値に基づいて変更することはできません。

class bar { 
public: 
    bar(some_type something) { 
     if (something == some_value) { 
      b.x = new A(3.14, 12.34); 
     } else { 
      b.x = new B(456.78); 
     } 
    } 
private: 
    int x_type; 
    std::unique_ptr<foo> x; 
    //... 
}; 

int main() { 
    bar b(whatever()); 
} 

この場合、あなたにもあることをfoo::~foo()を宣言する必要があります。この作品を作るための方法は、すべてのタイプstd::uniqe_ptr<foo>を持って、その後、実行時に動的にAまたはBオブジェクトを割り当てるxy、およびzを作ることです派生したオブジェクトが正しく破棄されるようにします。

x_typeと友人を完全に排除し、xの実際のタイプを気にしないコードを作成するのは一般的にはGood Idea™でしょう。

1

複数のテンプレートパラメータを持つテンプレートクラスをbarにすることが可能かどうかは疑問でしたが、パラメータタイプが別のパラメータに依存するかどうかはわかりません。

私はこれが役立つかどうかわかりませんが、私はそれをちょうどここに伝えます。あなたが見

、テンプレートの異なる専門分野が異なるクラスから継承することができます。あなたが持つことができるように:

// fwd decl 
template <int kind> class bar; 

template <> class bar<1> : public A { 
public: 
    bar(double x, double y) : A(x,y) { } 
}; 

template <> class bar<2> : public B { 
public: 
    bar(double a) : B(a) { } 
}; 

を後の段階では、あなたがclass C : public fooに来るとき、あなたはちょうどあなたがそれを持ってそこに新しいbarテンプレート特殊とに別のkindを割り当てる:統一名前としてbarを使用して(警告...しかしない統一タイプ - 。共通foo祖先以外にないbar<1>bar<2>は、2つの異なるタイプになります)

だから、あなたが相続したくない場合は[OK]を、あなたがそれをすることによって持つことができます異なる具体的にはbarテンプレートの専門化has-a

template <int kind> class bar; 

template <> class bar<1> { 
    A val; 
public: 
    bar(double x, double y) : val(x,y) { } 

    void doSomething2(...) { 
    // use the val of type A 
    } 
}; 
template <> class bar<2> { 
    B val; 
    double y_; 
public: 
    bar(double x, double y) : val(x), y_(y) { } 

    void doSomething2(...) { 
    // use the val of type B and a separate y_ 
    } 
}; 
1

のようにIかかわらテンプレートデータメンバを使用して、私は種類の値を取得どうやらその は、少なくともCでは不可能である コンストラクタ、タイプの定義について++ 11

C++ 11の適切なタイプを作成make_*テンプレート関数を使用して、いくつかのパラメータに応じてテンプレート構造を扱うの標準スキーマが付属していオブジェクト。例えば、 make_tuple関数:

auto t = std::make_tuple(1, "abc", 1.0); 
// decltype(t) == std::tuple<int, char const*, double> 

これはテンプレートクラスとテンプレート構築機能を作成することによって実現することができる:aに由来

template <class T> 
struct foo { 
    T t; 
    foo(T t): t(t) { } 
}; 

template <class T> 
foo<T> make_foo(T t) { return foo<T>(t); } 
2

xyzのために使用することができる全てのタイプである場合全て共通基底クラスの場合、ベースポインターの解はstd::unique_ptr(Lyubomir Stankovの場合は+1)となり、(IMHO)は良い解です。

しかし、 "複数のテンプレートパラメータを持つテンプレートクラスを作成することが可能かどうか"を尋ねました。

はい:可能です。本当にエレガントではありません(これまでのIMHO)が可能です。

私はそう願っています(役立つことができ、私は楽しみのために、次の解決策を提案するが、私は(私の例では、ABがよりfooから派生したものではない無関係なクラスであることに注意してください)、より一般的なケースでは、と思います)

#include <tuple> 
#include <string> 
#include <utility> 

class A 
{ 
    private: 
     double  d; 
     std::string s; 

    public: 
     A (double d0, std::string s0) : d { d0 }, s { s0 } { } 
}; 

class B 
{ 
    private: 
     long l; 

    public: 
     B (long l0) : l { l0 } { } 
}; 

template <typename Tx, typename Ty, typename Tz> 
class bar 
{ 
    private: 

     template <typename ... Ts> 
     using tpl = std::tuple<Ts...>; 

     template <std::size_t ... Is> 
     using is = std::index_sequence<Is...> const; 

     template <std::size_t N> 
     using mis = std::make_index_sequence<N>; 

     Tx x; 
     Ty y; 
     Tz z; 

     template <typename ... Tsx, std::size_t ... Isx, 
       typename ... Tsy, std::size_t ... Isy, 
       typename ... Tsz, std::size_t ... Isz> 
     bar (tpl<Tsx...> const & tx0, is<Isx...> const &, 
      tpl<Tsy...> const & ty0, is<Isy...> const &, 
      tpl<Tsz...> const & tz0, is<Isz...> const &) 
     : x { std::get<Isx>(tx0) ... }, 
      y { std::get<Isy>(ty0) ... }, 
      z { std::get<Isz>(tz0) ... } 
     { } 

    public: 

     template <typename ... Tsx, typename ... Tsy, typename ... Tsz> 
     bar (tpl<Tsx...> const & tx0, 
      tpl<Tsy...> const & ty0, 
      tpl<Tsz...> const & tz0) 
     : bar(tx0, mis<sizeof...(Tsx)> {}, 
       ty0, mis<sizeof...(Tsy)> {}, 
       tz0, mis<sizeof...(Tsz)> {}) 
     { } 
}; 

int main() 
{ 
    bar<A, B, A> aba{ std::make_tuple(2.3, "str1"), 
         std::make_tuple(4), 
         std::make_tuple(5.4, "str2") }; 

    bar<B, A, B> bab{ std::make_tuple(3), 
         std::make_tuple(3.2, "str3"), 
         std::make_tuple(5) }; 
} 

残念ながら、この例では、C++ 14個の機能ですstd::make_index_sequencestd::index_sequenceを使用しています。

あなたがC++ 11でfooを実装したい場合は、std::index_sequencestd::make_index_sequence

template <std::size_t ...> 
struct indexSeq 
{ }; 

template <std::size_t N, std::size_t ... Next> 
struct indexSeqHelper 
{ using type = typename indexSeqHelper<N-1U, N-1U, Next ... >::type; }; 

template <std::size_t ... Next > 
struct indexSeqHelper<0U, Next ... > 
{ using type = indexSeq<Next ... >; }; 

を代用して

template <std::size_t ... Is> 
    using is = indexSeq<Is...>; 

    template <std::size_t N> 
    using mis = typename indexSeqHelper<N>::type; 
関連する問題