2014-07-08 6 views
11

Gibt es eine Technik/besten Stil, um Klassenschablonenspezialisierungen für bestimmte Typen zu gruppieren?Gruppenklassenschablonenspezialisierungen

Ein Beispiel: Nehmen wir an ich eine Klassenvorlage haben Foo und ich brauche es die gleiche

für die typeset
A = { Line, Ray } 
für die typeset B

und auf eine andere Weise

B = { Linestring, Curve } 

spezialisiert haben

Was ich bisher mache: (die Technik wird auch präsentiert here für Funktionen)

#include <iostream> 
#include <type_traits> 
using namespace std; 

// 1st group 
struct Line {}; 
struct Ray  {}; 
// 2nd group 
struct Curve  {}; 
struct Linestring {}; 

template<typename T, typename Groupper=void> 
struct Foo 
{ enum { val = 0 }; }; 

// specialization for the 1st group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_same<T, Line>::value || 
    is_same<T, Ray>::value 
>::type> 
{ 
    enum { val = 1 }; 
}; 

// specialization for the 2nd group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_same<T, Curve>::value || 
    is_same<T, Linestring>::value 
>::type> 
{ 
    enum { val = 2 }; 
}; 

int main() 
{ 
    cout << Foo<Line>::val << endl; 
    cout << Foo<Curve>::val << endl; 
    return 0; 
} 

Eine zusätzliche Hilfsstruktur würde den Code verkürzen (und erlauben, die akzeptierten Typen direkt zu schreiben). Irgendwelche anderen Vorschläge, Korrekturen? Sollte dies nicht mit weniger Aufwand verbunden sein?

+3

Sie können auch eine * type_traits * nach Gruppe erstellen. – Jarod42

+0

@Angew: autsch, ich habe die Basisvorlage verpasst. Sie haben Recht, das sind zwei Spezialisierungen. –

Antwort

13

Sie können dies auch tun, mit Ihrem eigenen Eigenschaften und ohne enable_if:

// Traits 

template <class T> 
struct group_number : std::integral_constant<int, 0> {}; 

template <> 
struct group_number<Line> : std::integral_constant<int, 1> {}; 

template <> 
struct group_number<Ray> : std::integral_constant<int, 1> {}; 

template <> 
struct group_number<Linestring> : std::integral_constant<int, 2> {}; 

template <> 
struct group_number<Curve> : std::integral_constant<int, 2> {}; 


// Foo 

template <class T, int Group = group_number<T>::value> 
class Foo 
{ 
    //::: whatever 
}; 

template <class T> 
class Foo<T, 1> 
{ 
    //::: whatever for group 1 
}; 

template <class T> 
class Foo<T, 2> 
{ 
    //::: whatever for group 2 
}; 

Dies hat den Vorteil der automatisch sichergestellt hat, dass jede Art in höchstens einer Gruppe ist.

11

Zusatz Dereferenzierungsebene durch zwei neue Art Züge mit:

template<class T> 
struct is_from_group1: std::false_type {}; 

template<> 
struct is_from_group1<Line>: std::true_type {}; 

template<> 
struct is_from_group1<Ray>: std::true_type {}; 

template<class T> 
struct is_from_group2: std::false_type {}; 

template<> 
struct is_from_group2<Curve>: std::true_type {}; 

template<> 
struct is_from_group2<Linestring>: std::true_type {}; 

und tun dann die enable_if auf diese Art

// specialization for the 1st group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_from_group1<T>::value 
>::type> 
{ 
    enum { val = 1 }; 
}; 

// specialization for the 2nd group 
template<typename T> 
struct Foo<T, typename enable_if< 
    is_from_group2<T>::value 
>::type> 
{ 
    enum { val = 2 }; 
}; 

Hinweis Eigenschaften, die Sie noch benötigen, um sicherzustellen, dass keine User- Die definierte Klasse wird zu beiden Gruppen hinzugefügt, oder Sie erhalten eine Mehrdeutigkeit. Sie können entweder die Lösung von @ Angew aus einer nummerierten Gruppe mit std::integral_constant<int, N> für die Gruppennummer N ableiten. Oder, wenn diese Gruppen nicht logisch exklusiv sind, könnten Sie eine zusätzliche Bedingung innerhalb der enable_if hinzufügen, die dagegen schützt.