2017-06-11 6 views
0

私はこのコードを持っている:C++では、クラスの引数に応じて異なるジェネリック型を返す方法は?

template<class T1, class T2> 
class Pair 
{ 
private: 
    T1 first; 
    T2 second; 

public: 
    void SetFirst(T1 first) 
    { 
     this.first = first; 
    } 
    void SetSecond(T2 second) 
    { 
     this.second = second; 
    } 
    T1 GetFirst() 
    { 
     return first; 
    } 
    T2 GetSecond() 
    { 
     return second; 
    } 
}; 

どのようにして使用しなければならないジェネリック型パラメーターに応じて決定したものではなく、私が持っている4の、2つの方法SetValue()GetValue()を実装するだろうか?例えば、私はGetValue()メソッドがintのパラメータを1または2のいずれかとし、数値に応じてT1またはT2の変数を返すと考えています。しかし、私は戻り値の型を事前に知らないので、これを解決するにはどうにかしていますか?

+3

何かを取得して設定するゲッターとセッターがある場合は、単に公開してください。 –

+0

私はそれがあなたの問題を解決するかどうかは確かではありませんが、多分それはあなたにいくつかの啓発を提供するでしょう - std :: tupleとstd :: getを探してください。 – ArturFH

答えて

0

C++は静的に型指定されているため、引数は関数引数ではなくテンプレート引数でなければなりません。

そして、ユーザーごとに1つの機能のように見えますが、実際は2つです。

template <int i = 1> auto GetValue() -> std::enable_if_t<i == 1, T1> { return first; } 
template <int i = 2> auto GetValue() -> std::enable_if_t<i == 2, T2> { return second; } 
template <int i = 1> auto SetValue(T1 x) -> std::enable_if_t<i == 1> { first = x; } 
template <int i = 2> auto SetValue(T2 x) -> std::enable_if_t<i == 2> { second = x; } 

私は、テンプレート引数が正しい場合を除き、リターン型でSFINAEを使用して、考慮から機能を削除します。今すぐあなたのクラスができ

template <typename T> 
class wrap 
{ 
    private: 
     T elem; 

    public: 
     void set (T const & t) 
     { elem = t; } 

     T get() const 
     { return elem; } 
}; 

を次のように

1

あなたが望む何をすべきか理解してください、あなたが求めていない、まさにけど...ない

は私が定義されたラッパー基本クラスの使用を提案します

template <typename T1, typename T2> 
struct Pair : wrap<T1>, wrap<T2> 
{ 
    template <typename T> 
    void set (T const & t) 
    { wrap<T>::set(t); } 

    template <typename T> 
    T get() const 
    { return wrap<T>::get(); } 
}; 

として定義されるか、あなたがC++ 11と可変引数テンプレートを使用することができますし、定義した場合のタイプは、リストのN番目のタイプを取得するためにgetTypeを特色場合、今

template <typename ... Ts> 
struct Pair : wrap<Ts>... 
{ 
    template <typename T> 
    void set (T const & t) 
    { wrap<T>::set(t); } 

    template <std::size_t N, typename T> 
    void set (T const & t) 
    { wrap<typename getType<N, Ts...>::type>::set(t); } 

    template <typename T> 
    T get() const 
    { return wrap<T>::get(); } 

    template <std::size_t N> 
    typename getType<N, Ts...>::type get() 
    { return wrap<typename getType<N, Ts...>::type>::get(); } 
}; 

を次のようにあなたは、より柔軟な方法でPairを定義することができます

template <std::size_t I, typename, typename ... Ts> 
struct getType 
{ using type = typename getType<I-1U, Ts...>::type; }; 

template <typename T, typename ... Ts> 
struct getType<0U, T, Ts...> 
{ using type = T; }; 

set()の引数は、そうでない場合は、正しいベースクラスと正しい基本要素

Pair<int, long> p; 

    p.set(0); // set the int elem 
    p.set(1L); // set the long elem 

を選択することができ、インデックスを介して、あなたは書くことができます

T2

に等しい場合、これは動作しませんでした、明らかに

p.get<int>(); // get the int elem value 
    p.get<long>(); // get the long elem value 

    p.get<0U>(); // get the 1st (int) elem value 
    p.get<1U>(); // get the 2nd (long) elem value 

残念ながら、get()は、引数を受け取らないので、タイプは(インデックスタイプを介して、または経由)explicitedする必要があります

次は、この特定の状況では

#include <iostream> 

template <std::size_t I, typename, typename ... Ts> 
struct getType 
{ using type = typename getType<I-1U, Ts...>::type; }; 

template <typename T, typename ... Ts> 
struct getType<0U, T, Ts...> 
{ using type = T; }; 

template <typename T> 
class wrap 
{ 
    private: 
     T elem; 

    public: 
     void set (T const & t) 
     { elem = t; } 

     T get() const 
     { return elem; } 
}; 

template <typename ... Ts> 
struct Pair : wrap<Ts>... 
{ 
    template <typename T> 
    void set (T const & t) 
    { wrap<T>::set(t); } 

    template <std::size_t N, typename T> 
    void set (T const & t) 
    { wrap<typename getType<N, Ts...>::type>::set(t); } 

    template <typename T> 
    T get() const 
    { return wrap<T>::get(); } 

    template <std::size_t N> 
    typename getType<N, Ts...>::type get() 
    { return wrap<typename getType<N, Ts...>::type>::get(); } 
}; 

int main() 
{ 
    //Pair<int, int> p; compilation error 
    Pair<int, long, long long> p; 

    p.set(0); 
    p.set(1L); 
    p.set(2LL); 

    std::cout << p.get<int>() << std::endl;  // print 0 
    std::cout << p.get<long>() << std::endl;  // print 1 
    std::cout << p.get<long long>() << std::endl; // print 2 

    p.set<0U>(3); 
    p.set<1U>(4); 
    p.set<2U>(5); 

    std::cout << p.get<0U>() << std::endl; // print 3 
    std::cout << p.get<1U>() << std::endl; // print 4 
    std::cout << p.get<2U>() << std::endl; // print 5 
} 
0

(C++ 11)の完全実施例である、あなたは間違いなくstd::pairかを選ぶべきstd::tuple。(あなたがコンパイルエラーを持っていない場合は、区別することができT1T2を提供)

は、あなたは、単に SetValue()をオーバーロードすることができます

void SetValue(T1 x) 
{ first=x; } 

void SetValue(T2 x) 
{ second=x; } 

次に、とのコンパイラは、任意の呼び出しのためのベストマッチを見つけ、すなわち

Pair<int,double> p; 
p.SetValue(0); // sets p.first 
p.SetValue(0.0); // sets p.second 

GetValue()とすると、取得する要素の情報はp.GetValue()のように推測できませんので、何とか入力する必要があります。

auto a = p.GetValue<int>(); 
auto b = p.GetValue<double>(); 

のように使用するが、あなたの最初のバージョンが十分であるべきな

template<typename T> 
std::enable_if_t<std::is_same<T,T1>,T> 
GetValue() const 
{ return first; } 

template<typename T> 
std::enable_if_t<std::is_same<T,T2>,T> 
GetValue() const 
{ return second; } 

など、いくつかのオプションがあります。

関連する問題