2015-04-07 14 views
13

Si è verificato un problema relativo all'uso appropriato di enable_if e della specializzazione del modello.Specializzazione del modello e problemi enable_if

Dopo aver modificato l'esempio (per motivi di riservatezza), ecco un esempio simile:

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.

Il codice che ho finora sembra che questo -

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

Il codice di cui sopra non compila perché - Dice che sto ridefinendo il meno metodo.

Gli errori sono:

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. 

Qualcuno può indicare qual è l'errore qui?

+0

in sostanza non si utilizza 'enable_if' correttamente a causa del modo in cui si richiama il tipo restituito. – Alex

+0

La soluzione rapida consiste nell'aggiungere un parametro di ellissi '...' a uno dei modelli in modo che vengano considerati distinti sovraccarichi. – 0x499602D2

+1

Oppure modifica la firma (o le firme) in 'template :: value> :: type * = nullptr>' – vsoftco

risposta

18

Gli argomenti del modello predefinito non fanno parte della firma di un modello di funzione. Quindi nel tuo esempio hai due identici sovraccarichi di less, che è illegale. clang lamenta la ridefinizione del argomento di default (che è anche illegale in base alla §14.1/12 [temp.param]), mentre gcc produce il seguente messaggio di errore:

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

Per correggere l'errore spostare il enable_if espressione da argomento di default per un parametro di modello fittizio

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) { 
    // .... 
} 

Un'altra opzione è quella di utilizzare enable_if nel tipo di ritorno, anche se sento che questo è più difficile da leggere.

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

Tecnicamente, il primo set di codice è mal formato secondo lo standard, poiché 'void *' non è un tipo valido per un parametro non di tipo template. In pratica, nessun compilatore che io sappia di cui ci importi veramente. La soluzione è banale, però. –

+0

@ T.C. TIL ... grazie per averlo indicato – Praetorian

+0

L'ho modificato come parametro di funzione e ora funziona – user855