2017-12-19 2 views
2

Ich bin ein bisschen verwirrt über partielle Template-Spezialisierung ... Ich habe einige Code, der auf einem arithmetischen Datentyp T und auf einer kleinen ganzen Zahl DIM abhängt. Ich möchte in der Lage sein, verschiedene Klassenmethoden für verschiedene DIM-Werte anzugeben. Die Unmöglichkeit, eine teilweise Template-Spezialisierung zu verwenden, führte mich dazu, enable_if zu erkunden. Es ist genau das, was ich brauchte ... außer dass ich eine Nummer und keinen Typ zurückgeben möchte. Wie kann ich das machen? Der folgende Code sollte veranschaulichen, was ich möchte.C++ enable_if für Nicht-Typ Vorlage Parameter

#include <stdio.h> 
#include <iostream> 
#include <type_traits> 

template <typename T, int DIM> 
class foo{ 
    public: 
     T function(); 

}; 


template <typename T, int DIM> 
T foo<T, std::enable_if<DIM == 1>::value>::function(){ 
    // do something 
    return 1.0; 
} 

template <typename T, int DIM> 
T foo<T, std::enable_if<DIM == 2>::value>::function(){ 
    // do something else 
    return 2342.0; 
} 

int main(){ 
    foo<int, 1> object; 
    int ak = object.function(); 
    std::cout << ak << "\n"; 

    return 0; 
} 

Antwort

5

Sie können völlig tun, was Sie mit enable_if wollen, nur nicht vergessen, hat die Substitution, wenn die Bedingung zum Scheitern verurteilt ist falsch, also müssen Sie type aufrufen, um sicherzustellen, dass die Substitution fehlschlägt, wenn Sie sich auf verschiedene Bedingungen spezialisieren.

#include <stdio.h> 
#include <iostream> 
#include <type_traits> 

template <typename T, int DIM> 
class foo 
{ 
public: 
    template <int D = DIM> 
    typename std::enable_if<D == 1, T>::type 
    function() 
    { 
     // do something 
     return 1.0; 
    } 

    template <int D = DIM> 
    typename std::enable_if<D == 2, T>::type 
    function() 
    { 
     // do something else 
     return 2342.0; 
    } 

}; 

int main(){ 
    foo<int, 1> object; 
    int ak = object.function(); 
    std::cout << ak << "\n"; 

    return 0; 
} 

Für einfache Szenarien, wie die oben (wo Sie einen bestimmten Wert überprüfen, anstatt einen Wertebereich), können Sie auch teilweise Spezialisierung verwenden. Aber wenn Sie sich spezialisieren möchten, sagen Sie, für alle Werte von 1-50, ein anderer für 51-200, und dann einen generischen Fall durch, enable_if funktioniert super.

Sie können auch enable_if in der Vorlagensignatur verwenden. Nur ein kurzes Beispiel.

#include <stdio.h> 
#include <iostream> 
#include <type_traits> 

template <typename T, int DIM> 
class foo 
{ 
public: 
    template <int D = DIM, typename std::enable_if<D == 1, void>::type* = nullptr> 
    T function() 
    { 
     // do something 
     return 1.0; 
    } 

    template <int D = DIM, typename std::enable_if<D == 2, void>::type* = nullptr> 
    T function() 
    { 
     // do something else 
     return 2342.0; 
    } 

}; 

int main(){ 
    foo<int, 1> object; 
    int ak = object.function(); 
    std::cout << ak << "\n"; 

    return 0; 
} 
+2

Schön, aber ich denke, es ist möglich, es ein wenig einfacher zu machen: ist nicht notwendig jeden Template-Parameter ('U' und' D') zu spiegeln, um SFINAE zu aktivieren: es ist genug ein Template-Parameter in der 'std :: enable_if' Test beteiligt . Also sollte einfach als 'Vorlage :: type * = nullptr> T function() '(und' void' ist der Standard zurückgegebene Typ für 'std :: enable_if' – max66

+2

Or auch 'template typenname std :: enable_if :: type function()' – max66

+0

@ max66 Ich habe es nur explizit gemacht (ich bin ursprünglich ein Python-Programmierer, also vor allem bei der Erklärung von Konzepten, ich mag explizite über implizit), aber ja Beide sind absolut gültige Vorschläge, und ich würde Ihren Stil für den Produktionscode verwenden. Obwohl das Entfernen von "U = T" eigentlich ein großartiger Gesamtvorschlag ist. Editiert. –

0

Verwenden Sie die std :: integral_constant Typ Ihre Werte zu wickeln, wie in:

std::integral_constant<int, 2> 
+0

Danke für die Anregung, aber darf ich fragen, warum? – Sermal

1

Sie können teilweise spezialisieren, die ganze Klasse:

template <typename T, int DIM> 
class foo; 

template <typename T> 
class foo<T, 1> 
{ 
public: 
    T function() { 
     // do something 
     return 1.0; 
    } 
}; 

template <typename T> 
class foo<T, 2> 
{ 
public: 
    T function() { 
     // do something 
     return 2342.0; 
    } 
}; 

Wenn Sie viele gemeinsamen Code zwischen dem beide Spezialisierung haben, können Sie immer noch Vererbung (erbt von gemeinsamem Teil oder nur das Fach Teil).

Eine einfache alternative Möglichkeit ist Tag Disposition zu verwenden:

template <typename T, int dim> 
class foo 
{ 
public: 
    T function(); 
}; 

template <typename T> 
T function_helper(foo<T, 1>&) { 
    // do something 
    return 1.0; 
} 

template <typename T> 
T function_helper(foo<T, 2>&) { 
    // do something 
    return 2342.0; 
} 

template <typename T, int dim> 
T foo::function() { 
    return function_helper(*this); 
} 
+0

Ich wählte die andere Antwort, weil sie mein Problem löste und expliziteren Code lieferte , aber das ist sehr interessant! Vielen Dank für den Vorschlag! – Sermal

Verwandte Themen