2017-06-10 2 views
1

だからここでは単純化の問題がある、私はテンプレートを作成したい我々は二つのタイプ がどのようにパラメータ化された型の特定のメンバーの種類に基づいて、テンプレートクラスの機能の異なる実装を持つことが

struct Shape2D 
{ 
    Vec2 Position; 
}; 

struct Shape3D 
{ 
    Vec3 Position; 
}; 

があるとしクラステスト

template<class T> 
class Test 
{ 
    public: 
     int method1() 
     { 
      //return 1 if member T::Position is Vec2, 
      //return 2 if member T::Position is Vec3 
     } 
} 

次のコードが動作するよう

Test<A> ta; 
Test<B> tb; 
assert(ta.method1() == 1); 
assert(tb.method1() == 2); 

リアルにこの問題の背景は、OpenGLエンジンの場合です。私は、3Dと2Dのバージョンを書くことなく、2Dと3Dの頂点データに同じシリアル化クラスを使用できるようにしたい。あなたが別のコードを実行するために、いくつかのoveload機能を持たせることができる

+0

多型ではなく、テンプレートに関連する問題。 shape3dとshape2dを形から派生させることは可能でしょうか? –

+0

すべては、ここで達成したいと思うものによって異なります。適切なクラスが作成されているかどうかをテストしたいだけですか? –

+0

こんにちは。できるだけシンプルに問題を解決しようと多くの努力をしましたが、実際にはそれとはまったく異なっていました。手元に問題がある場合は、オーバーロードが最善の解決策です。 – alcoforado

答えて

0

、あなたがint func (shape 2D x)int func (shape3D x)を持っていると言う、あなたのmethod1あなただけfunc (T.position)を呼び出すと、コンパイラは、あなたが電話を解決するのに役立ちますint型ので。

1

これにはいくつかの方法があります。これは、あなたが実際にTのインスタンスを持っていることが必要です

template<class T> 
class Test 
{ 
private: 
    T myT; 

    int internal(Vec2) 
    { 
     return 1; 
    } 

    int internal(Vec3) 
    { 
     return 2; 
    } 
public: 
    Test() : myT{} {} 

    int method1() 
    { 
     return internal(myT.Position); 
    } 
}; 

最も簡単なのは、単に通常のオーバーロードの解決を使用することです。そうしないと、テンプレートベースのアプローチを使用する必要があります。それはかなり深い話題ですが、あなたはあなたの例では何をしたいん一つのアプローチはこれです:

template <typename T> 
int internal(); 

template <> 
int internal<Vec2>() 
{ 
    return 1; 
} 

template <> 
int internal<Vec3>() 
{ 
    return 2; 
} 

template<class T> 
class Test 
{ 
public: 
    int method1() 
    { 
     return internal<decltype(T::Position)>(); 
    } 
}; 
1

あなたは解決するための関数宣言(定義は、この場合に必要とされていない)、std::declvalstd::integral_constantのカップルを使用することができますそれはコンパイル時に。上記溶液はTという名前のデータメンバPositionVec2又はVec3のいずれかであるの種類をしていない場合はコンパイルに失敗し

#include<type_traits> 
#include<utility> 

struct Vec2 {}; 
struct Vec3{}; 

struct Shape2D { Vec2 Position; }; 
struct Shape3D { Vec3 Position; }; 

template<class T> 
class Test { 
    static constexpr std::integral_constant<int, 1> method1(Vec2); 
    static constexpr std::integral_constant<int, 2> method1(Vec3); 

public: 
    constexpr int method1() { 
     return decltype(method1(std::declval<T>().Position))::value; 
    } 
}; 

int main() { 
    Test<Shape2D> ta; 
    Test<Shape3D> tb; 
    static_assert(ta.method1() == 1, "!"); 
    static_assert(tb.method1() == 2, "!"); 
} 


最小の、実施例に続きます。


この可能性が代わりにデフォルト値を必要とする別の可能なアプローチ:

constexpr int method1() { 
    return 
     (std::is_same<decltype(std::declval<T>().Position), Vec2>::value 
     ? 1 : (std::is_same<decltype(std::declval<T>().Position), Vec3>::value 
     ? 2 : 0)); 
} 

std::is_sameと組み合わせて使用​​する三項演算子、より多くの何もないです。


あなたがC++ 17を使用することができれば、あなたもif/else constexprにあなたのソリューションをベースにすることができます

constexpr int method1() { 
    if constexpr(std::is_same_v<decltype(std::declval<T>().Position), Vec2>) { 
     return 1; 
    } else if constexpr(std::is_same_v<decltype(std::declval<T>().Position), Vec3>) { 
     return 2; 
    } 
} 
関連する問題