2015-04-07 21 views
13

Występuje problem dotyczący właściwego użycia funkcji enable_if i specjalizacji szablonu.Specjalizacje szablonów i problemy z włączonym_aktywnym interfejsem użytkownika

Po modyfikacji przykładu (ze względu na poufność), tutaj jest porównywalny przykład:

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.

kod, który do tej pory wygląda to tak -

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

Powyższy kod nie skompilować ponieważ - Mówi, że redefiniuję mniej metody.

Błędy są:

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. 

Czy ktoś może wskazać, co jest błędem tutaj?

+0

zasadniczo nie używasz 'enable_if' poprawnie z powodu sposobu wywołania typu zwracanego. – Alex

+0

Szybkie rozwiązanie polega na dodaniu parametru "..." elipsy do jednego z szablonów, aby były uważane za wyraźne przeciążenia. – 0x499602D2

+1

Lub zmień podpis (y) na 'szablon :: value> :: type * = nullptr>' – vsoftco

Odpowiedz

18

Domyślne argumenty szablonu nie są częścią sygnatury szablonu funkcji. Więc w twoim przykładzie masz dwa identyczne przeciążenia z less, co jest nielegalne. dzyń narzeka redefinicji domyślnym argumentem (który jest również nielegalne zgodnie z §14.1/12 [temp.param]), podczas gdy GCC produkuje się następujący komunikat o błędzie:

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

naprawić błąd przesunąć ekspresji enable_if z domyślnym argumentem do manekina parametru szablonu

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

Inną opcją jest użycie enable_if w rodzaju powrotu, choć czuję, że to jest trudniejsze do odczytania.

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

Technicznie, pierwszy zestaw kodu jest źle sformułowany zgodnie ze standardem, ponieważ 'void *' nie jest poprawnym typem dla parametru szablonu bez typu. W praktyce żaden kompilator, o którym mi wiadomo, nie dba. Poprawka jest jednak trywialna. –

+0

@ T.C. TIL ... dzięki za wskazanie, że – Praetorian

+0

Zmieniłem go, aby był parametrem funkcji i teraz działa – user855