2015-04-07 7 views
13

Ich stoße auf ein Problem in Bezug auf die angemessene Verwendung von enable_if und Template-Spezialisierung.Template-Spezialisierung und enable_if Probleme

Nach dem Beispiel Modifizieren (aus Gründen der Vertraulichkeit), ist hier ein vergleichbares Beispiel:

I have function called "less" that checks if 1st arg is less than 2nd arg. Let's say I want to have 2 different kinds of implementations depending on the type of input - 1 implementation for integer and another for double.

Der Code, den ich habe so sieht weit wie diese -

#include <type_traits> 
#include <iostream> 

template <class T, 
      class = typename std::enable_if<std::is_floating_point<T>::value>::type> 
    bool less(T a, T b) { 
    // .... 
} 

template <class T, 
      class = typename std::enable_if<std::is_integral<T>::value>::type> 
    bool less(T a, T b) { 
    // .... 
} 

int main() { 
    float a; 
    float b; 
    less(a,b); 
    return 0; 
} 

Der obige Code nicht kompiliert weil - Es sagt, dass ich die weniger Methode neu definiere.

Fehler sind:

Z.cpp:15:19: error: template parameter redefines default argument 
      class = typename std::enable_if<std::is_integral<T>::value>::type> 

       ^
Z.cpp:9:19: note: previous default template argument defined here 
      class = typename std::enable_if<std::is_floating_point<T>::value>::type> 
       ^

Z.cpp:16:11: error: redefinition of 'less' 
    bool less(T a, T b) { 
     ^

Z.cpp:10:11: note: previous definition is here 
    bool less(T a, T b) { 
     ^

Z.cpp:23:5: error: no matching function for call to 'less' 
    less(a,b); 
    ^~~~ 

Z.cpp:15:43: note: candidate template ignored: disabled by 'enable_if' 
     [with T = float] 
      class = typename std::enable_if<std::is_integral<T>::value>::type> 
             ^
3 errors generated. 

Kann jemand darauf hinweisen, was der Fehler ist hier?

+0

Im Wesentlichen verwenden Sie 'enable_if' nicht korrekt, da Sie den Rückgabetyp aufrufen. – Alex

+0

Schnelle Lösung besteht darin, einen Ellipsenparameter '...' zu einem der Templates hinzuzufügen, so dass sie als unterschiedliche Überladungen betrachtet werden. – 0x499602D2

+1

Oder ändern Sie die Signatur (en) in 'template :: Wert> :: type * = nullptr>' – vsoftco

Antwort

18

Standardschablonenargumente sind nicht Teil der Signatur einer Funktionsschablone. In Ihrem Beispiel haben Sie also zwei identische Überladungen von less, was illegal ist. Klirren beklagt sich über die Neudefinition des Standardargument (was auch nach illegal ist §14.1/12 [temp.param]), während gcc folgende Fehlermeldung erzeugt:

error: redefinition of ' template<class T, class> bool less(T, T) '

um den Fehler zu beheben, um das enable_if Ausdruck bewegen von Standardargument zu einem Dummy-Template-Parameter

template <class T, 
      typename std::enable_if<std::is_floating_point<T>::value, int>::type* = nullptr> 
    bool less(T a, T b) { 
    // .... 
} 

template <class T, 
      typename std::enable_if<std::is_integral<T>::value, int>::type* = nullptr> 
    bool less(T a, T b) { 
    // .... 
} 

eine weitere Option ist enable_if im Rückgabetyp zu verwenden, obwohl ich finde, dass die schwieriger zu lesen ist.

template <class T> 
     typename std::enable_if<std::is_floating_point<T>::value, bool>::type 
     less(T a, T b) { 
    // .... 
} 

template <class T> 
    typename std::enable_if<std::is_integral<T>::value, bool>::type 
    less(T a, T b) { 
    // .... 
} 
+0

Technisch ist der erste Satz von Code schlecht gebildet gemäß dem Standard, weil 'void *' kein gültiger Typ für einen Template-Nicht-Typparameter ist. In der Praxis interessiert mich kein Compiler, den ich kenne. Die Lösung ist jedoch trivial. –

+0

@ T.C. TIL ... danke, dass ich das herausgebracht habe – Praetorian

+0

Ich habe es zu einem Funktionsparameter geändert und das funktioniert jetzt – user855