2013-02-22 14 views
5

Iは、次のクラスがあるとしますテンプレートパラメータが異なるマッピングをC++推論テンプレート引数

template <class T, class U, class V> Foo 
{ 
    ... 
}; 

持っているので、私はTが何であるかに基づいて、他のテンプレート引数UとVを推定することができます。たとえば、Tがdoubleの場合、UとVは常にクラスD1とD2になり、Tがfloatの場合、UとVは他のクラスF1とF2になります。

これを念頭に置いて、私は1つのテンプレート引数だけを渡すことができ、コンパイラに他の2つのパラメータを推測させる方法がありますか?

私は単純な答えは、これらの他のクラスもテンプレート化してテンプレート引数Tをそれらに渡すことだと知っていますが、これらのクラスをテンプレート化することはできません(これらはツールによって自動生成されます)。

理想的には私はそうのようなのtypedefかに#defineを使用することができるだろう:

typedef Foo<double> Foo<double, D1, D2> 
typedef Foo<float> Foo<float, F1, F2> 

しかし、これらはコンパイルされません。私はテンプレートのメタプログラミングやテンプレートテンプレートのパラメータを使ってこの問題を解決する方法があるのだろうかと思っていますが、私はそれらの概念を頭に入れているようには思えません。誰にもアイデアはありますか?

答えて

5

Angewによって与えられた答えは、あなたに適切なアプローチを示しているが、UVを推定することができないとインスタンス化するクライアントによって提供されなければならない状況に対処する方法をお見せしません。このような場合を扱うために

、あなたはテンプレートのデフォルト引数を割り当てることができUVパラメータ:

struct D1 { }; struct D2 { }; 
struct F1 { }; struct F2 { }; 

// Primary template 
template<typename T> 
struct deduce_from 
{ 
}; 

// Specialization for double: U -> D1, V -> D2 
template<> 
struct deduce_from<double> 
{ 
    typedef D1 U; 
    typedef D2 V; 
}; 

// Specialization for float: U -> F1, V -> F2 
template<> 
struct deduce_from<float> 
{ 
    typedef F1 U; 
    typedef F2 V; 
}; 

// Give defaults to U and V: if deduce_from is not specialized for 
// the supplied T, and U or V are not explicitly provided, a compilation 
// error will occur 
template< 
    typename T, 
    typename U = typename deduce_from<T>::U, 
    typename V = typename deduce_from<T>::V 
    > 
struct Foo 
{ 
    typedef U typeU; 
    typedef V typeV; 
}; 

そしてここでは、上記溶液の正しさをテストするための簡単なプログラムです:

#include <type_traits> 

int main() 
{ 
    static_assert(std::is_same<Foo<double>::typeU, D1>::value, "Error!"); 
    static_assert(std::is_same<Foo<double>::typeV, D2>::value, "Error!"); 
    static_assert(std::is_same<Foo<float>::typeU, F1>::value, "Error!"); 
    static_assert(std::is_same<Foo<float>::typeV, F2>::value, "Error!"); 

    // Uncommenting this will give you an ERROR! 
    // No deduced types for U and V when T is int 
    /* static_assert(
     std::is_same<Foo<int>::typeU, void>::value, "Error!" 
     ); */ 
    static_assert(
     std::is_same<Foo<int, bool, char>::typeU, bool>::value, "Error!" 
     ); // OK 
    static_assert(
     std::is_same<Foo<int, bool, char>::typeV, char>::value, "Error!" 
     ); // OK 
} 
+0

ありがとう!これは完全に機能します。 – thompsonja

+0

@thompsonja:喜んで助けました:-) –

6

あなたはこのように、UVを取り除くことができます:deduce_fromは控除のプロセスをカプセル化し

template <typename T> 
struct Foo 
{ 
    typedef typename deduce_from<T>::U U; 
    typedef typename deduce_from<T>::V V; 
}; 

+0

'deduce_from'のようなクラスは、しばしば「特性クラス」として知られています。 –

+0

ありがとう!あなたの答えはAndy'sと一緒に問題の解決に役立ちました。 – thompsonja

関連する問題