2013-02-22 12 views
5

Angenommen, ich habe die folgende Klasse:C++ deduziert template Argumente auf der Grundlage anderer Vorlage Argumente

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

Die Template-Parameter haben eine deutliche Abbildung, so dass ich die anderen Template Argumente ableiten U und V auf Basis welcher T ist . Zum Beispiel, wenn T doppelt ist, werden U und V immer einige Klassen D1 und D2 sein, und wenn T float ist, werden U und V immer einige andere Klassen F1 und F2 sein.

Mit diesem Hintergedanken, gibt es eine Möglichkeit, dass ich nur ein Template-Argument übergeben kann, und der Compiler die anderen beiden Parameter ableiten?

Ich weiß, die einfache Antwort wäre, diese anderen Klassen auch templated zu machen und das Vorlagenargument T an sie zu übergeben, aber ich bin nicht in der Lage, diese Klassen templated zu machen (sie werden automatisch von einem Werkzeug generiert).

Idealerweise würde ich in der Lage sein, wie so typedef oder #define zu verwenden:

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

jedoch diese nicht kompilieren. Ich frage mich, ob es eine Möglichkeit gibt, Template-Metaprogrammierungs- oder Template-Template-Parameter zu verwenden, um dieses Problem zu lösen, aber ich kann meinen Kopf nicht mit diesen Konzepten umhüllen, und ich habe das Gefühl, dass es eine noch einfachere Antwort gibt. Hat jemand Ideen?

Antwort

5

Die Antwort von Angew zeigt Ihnen den richtigen Ansatz, aber nicht Sie zeigt, wie man mit Situationen fertig zu werden, wo U und V können nicht abgeleitet werden, und muss vom instanziierenden Client zur Verfügung gestellt werden.

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; 
}; 

Und hier ist ein einfaches Programm zu testen, um die Richtigkeit der obigen Lösung:

#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

Danke! Das funktioniert perfekt. – thompsonja

+0

@thompsonja: Froh, dass es geholfen hat :-) –

6

Sie los U bekommen konnte und V, wie folgt aus:

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

wo deduce_from den Abzug Prozess kapselt.

+0

diesen Fall zu behandeln, können Sie Standardargumente für die Template-Parameter U und V zuweisen Eine Klasse wie "deducce_from" wird oft als "Merkmalsklasse" bezeichnet. –

+0

Danke! Ihre Antwort in Kombination mit Andy hat mir geholfen, das Problem zu lösen. – thompsonja

Verwandte Themen