2015-02-02 3 views
5

eine Klassenvorlage und Hilfs Enum-Klassen definiert Betrachten Sie wie folgt vor:Vorlage Klasse, die aus den Permutationen ihrer Argumente unabhängig ist

enum class Color {Red, Green, Blue} 
enum class ShowAxes {False, True} 
enum class ShowLabels {False, True} 

template< Color, ShowAxes, ShowLabels > 
class A 
{......}; 

Die Frage ist, wie die Klasse A neu zu definieren, die auf unabhängig sein würde die Permutationen seiner Argumente. Ich benutze Dev C++, das C++ 11 unterstützt.

[EDIT]

Zum Beispiel sollte die neue Version von A

A< Color::Red, ShowAxes::True, ShowLabels::True > 
A< Color::Red, ShowLabels::True, ShowAxes::True > 
A< ShowAxes::True, Color::Red, ShowLabels::True > 
A< ShowLabels::True, Color::Red, ShowAxes::True > 
A< ShowLabels::True, Color::Red, ShowAxes::True > 
A< ShowAxes::True, Color::Red, ShowLabels::True > 

Versionen unterstützen, und alle von ihnen sind identisch, das heißt sie die gleiche Klasse zu generieren.

+0

C++ Klasse Template-Spezialisierung? –

+1

@BryanChen Sie können die Arten von Parametern mit einer Spezialisierung –

+0

nicht ändern Ich möchte nicht die Arten von Parametern ändern. Die Spezialisierung ist eine gute Idee, aber ich habe 3! = 6 Permutationen. Außerdem werde ich weitere Parameter hinzufügen. –

Antwort

5

Es ist nicht möglich mit Ihrer aktuellen Schnittstelle nicht-type Parameter zu verwenden.

Sie können stattdessen Typ Parameter übernehmen und die Werte in einer std::integral_constant wickeln:

template<class X, class Y, class Z> 
class A { /* stuff */ }; 

// use as: 
A<std::integral_constant<Color, Color::Red>, 
    std::integral_constant<ShowAxes, ShowAxes::True>, 
    std::integral_constant<ShowLabels, ShowLabels::True>> a; 

Das ist ziemlich ausführlich, so dass Sie ein Makro schreiben könnte in Erwägung ziehen:

#define AS_IC(Value) std::integral_constant<decltype(Value), Value> 

und schreiben als

A<AS_IC(Color::Red), AS_IC(ShowAxes::True), AS_IC(ShowLabels::True)> a; 

Den Wert des gewünschten Typs aus der Liste 0 extrahierens ist einfach:

template<class Result, class...> 
struct extract; 

template<class Result, Result Value, class... Tail> 
struct extract<Result, std::integral_constant<Result, Value>, Tail...> : std::integral_constant<Result, Value> {}; 

template<class Result, class Head, class... Tail> 
struct extract<Result, Head, Tail...> : extract<Result, Tail...> {}; 

Dann können Sie

tun
// inside the definition of A 
static constexpr Color col = extract<Color, X, Y, Z>::value; 

Demo.

Dies kann jedoch nicht erzeugen, die gleiche Klasse, aber Sie können eine Klassenvorlage A_impl, die wie Ihre A mit nicht-Typ Parametern verhält sich machen, und dass die tatsächliche Umsetzung enthält, und dann A eine Alias-Vorlage machen:

template< Color, ShowAxes, ShowLabels > 
class A_impl 
{/* stuff */}; 

template<class X, class Y, class Z> 
using A = A_impl<extract<Color, X, Y, Z>::value, 
       extract<ShowAxes, X, Y, Z>::value, 
       extract<ShowLabels, X, Y, Z>::value>; 

Jetzt gegeben

A<AS_IC(Color::Red), AS_IC(ShowAxes::True), AS_IC(ShowLabels::True)> a; 
A<AS_IC(Color::Red), AS_IC(ShowLabels::True), AS_IC(ShowAxes::True)> b; 

a und b denselben Typ haben. Demo.

Als Alternative können Sie auch decltype und Überlastungen Funktionsschablonen verwenden, aber das erfordert eine Funktion Template-Deklaration für jede mögliche Reihenfolge der Typen ergänzt:

template< Color c, ShowAxes a, ShowLabels l> 
A<c,a,l> A_of(); 

template< ShowAxes a, ShowLabels l, Color c> 
A<c,a,l> A_of(); 

// etc. 

decltype(A_of<Color::Red, ShowAxes::True, ShowLabels::True>()) a1; 
decltype(A_of<ShowAxes::True, ShowLabels::True, Color::Red>()) a2; 
+0

Die Idee von 'std :: integral_constant' und' extract' sieht gut aus. Ich werde über die Optimierung des Codes nachdenken. –

+0

Ich habe eine kleine (vielleicht triviale) Frage. Ist es möglich, ein Makro AS_IC durch ein nicht-direktives Personal zu ersetzen, zB eine Klassenvorlage oder eine Template-Funktion? –

+1

@VahagnPoghosyan Kein makro-freier Weg, den ich kenne, ohne eine Menge zu addieren, wenn Sie ein 'A' erklären. –

0

Vielleicht mit std::is_same. Dann können Sie Ihren Code auf diese Weise vereinfachen:

template <typename A, typename B, typename C> 
class X 
{ 
public: 
    X() { 
     static_assert(
      std::is_same<A, Color>::value || 
      std::is_same<B, Color>::value || 
      std::is_same<C, Color>::value, 
      "nope"); 
     // other assertions here! 
     // also, make sure your types are different ;) 
    } 
    X(A a, B b, C c) : X() { 
     // your code here 
    } 
}; 

template <typename A, typename B, typename C> 
X<A, B, C> make(A a, B b, C c) { 
    // possible verifications here 
    return X<A, B, C>(a, b, c); 
} 

int main() { 
    auto a = make(Color::Red, ShowAxes::true, ShowLabels::True); 
    return 0; 
} 

Sie können

Es tut mir leid, alle Ihre Typen A, B & C. überprüfen, aber ich sehe keine andere Lösung sehen. :/

+2

OP-Code erwartet nicht-type Template-Parameter –

+0

Ich habe einen Text in der Frage für die detaillierte Erklärung meines Ziels hinzugefügt. –

+0

Ich habe meinen Beitrag bearbeitet. – vincentp

Verwandte Themen