2017-07-07 1 views
0

J'ai le code suivant:std :: enable_if fondée sur std :: is_convertible pas correctement modèle déduisant

#include <iostream> 
#include <type_traits> 

template <typename T, typename std::enable_if 
           <std::is_convertible<int, T>::value, T>::type> 
void func(T a) 
{ 
    std::cout << a << std::endl; 
} 

template <typename T, typename std::enable_if 
           <!std::is_convertible<int, T>::value, T>::type> 
void func(T a) 
{ 
    a.print(); 
} 

class Test 
{ 
public: 
    void print() 
    { 
     std::cout << "Test" << std::endl; 
    } 
};  

int main() 
{ 
    func(3); 
    func("Test"); 
    return 0; 
} 

Avec ce code, j'attendu le premier appel à func pour imprimer 3 (comme int est en effet convertible à int, la première spécialisation devrait être appelée) et le deuxième appel à func pour imprimer Test (Test() n'est pas convertible en int, donc la deuxième spécialisation devrait être appelée). Cependant, je hériterez d'une erreur du compilateur:

prog.cpp: In function ‘int main()’:

prog.cpp:27:8: error: no matching function for call to ‘func(int)’

prog.cpp:5:6: note: candidate: template [class T, typename std::enable_if[std::is_convertible[int, T>::value, T>::type > void func(T)

prog.cpp:5:6: note: template argument deduction/substitution failed:

prog.cpp:27:8: note: couldn't deduce template parameter ‘[anonymous>’

Cependant, si je change les fonctions templated être à la place (tout en laissant tout le reste exactement la même chose):

template <typename T, typename std::enable_if 
           <std::is_convertible<int, T>::value, T>::type* = 
            nullptr> 
void func(T a) 
{ 
    std::cout << a << std::endl; 
} 

template <typename T, typename std::enable_if 
           <!std::is_convertible<int, T>::value, T>::type* = 
            nullptr> 
void func(T a) 
{ 
    a.print(); 
} 

puis tout compile et œuvres comme je l'attendais. Que fait cette syntaxe supplémentaire et pourquoi en ai-je besoin?

+0

dupliquer de [Comment fonctionne std :: enable \ _fonctionnement?] (Https://stackoverflow.com/questions/25284499/how-does-stdenable-if-work) –

Répondre

4
template<typename T, typename std::enable_if<std::is_convertible<int, T>::value, T>::type> 

si nous devions éliminer le bruit, deviendrait

template<typename T, typename Something<T>::type> 

qui déclare que son second paramètre un paramètre non-type, le typename ici spécifie la type imbriqué est un nom d'un type. Voir here pour plus d'informations.

Dans le premier cas, le deuxième paramètre est non-type, donc l'appel de fonction func(3) ne correspond pas au modèle qui attend func<int, some_int>(3).

+0

@downvoter veuillez expliquer, je suis intrigué comme pourquoi cela est perçu comme downvote digne –

+0

Vous n'avez pas répondu à la question. J'ai noté dans la question elle-même que fournir un paramètre par défaut de 'nullptr' a résolu le problème - pourquoi le paramètre par défaut est-il nécessaire? –

+1

@R_Kapp J'ai répondu avec les trois premières phrases. Tout ce qui suit est ajouté parce que je suppose que vous n'êtes pas familier avec SFINAE. –