2

Si vous avez cette fonction générique:modèle fonction méthode invocation C++ ne peut pas appeler des méthodes surchargées

template<class type, class ret, class atype1, class atype2, class atype3> 
ret call3(type *pClass, ret(type::* funcptr)(atype1, atype2, atype3), atype1 arg, atype2 arg2, atype3 arg3) 
{ 
    //do some stuff here 
    return (pClass->*funcptr)(arg, arg2, arg3); 
} 

et vous faites ceci:

class MyClass 
{ 
    public: 
    void test(int, int, int){}; 
    void test(int, int){}; 
    void test(int, int, const char *){}; //comment this line, and it works fine. 
}; 

... 

    MyClass *a = new MyClass(); 
    call3(a, &MyClass::test, 1, 2, 3); 

g ++ dira:

no matching function for call to `call3(MyClass*&, <unknown type>, int, int, int)' 

Y at-il un moyen de résoudre ce problème? (Mon code est probablement très mauvais aussi puisque je ne suis pas très bon en C++.)

+1

Lorsque 'ret' est lié à' void', ne se plaint-il pas d'une fonction vide retournant une valeur? –

+0

Aucune plainte pour moi ... Je ne sais pas pourquoi. – jcao219

+0

Renvoyer void à partir d'une fonction renvoyant void est valide, uniquement pour que ce type de casse-bordure soit plus simple dans un code basé sur un modèle. –

Répondre

3

Vous pouvez spécifier explicitement le modèle à utiliser.

call3<MyClass, void, int, int, int>(a, &MyClass::test, 1, 2, 3); 

Si vous rearange l'ordre de vos paramètres de modèle, vous pouvez obtenir le MyClass et non avenue déduite de l'argument, si l'appel en ayant besoin d'une surcharge ressemblera à ceci:

call3<int,int,int>(a, &MyClass::test, 1, 2, 3) 

Notez que quand vous ne réellement besoin la résolution de surcharge explicite, il peut encore être

call3(a, &MyClass::otherfunction, 1,2,3); 
+0

Celui où les paramètres du template sont réorganisés semble avoir fonctionné. Je vous remercie! – jcao219

0

Le compilateur ne peut pas déduire le type de paramètre de retour. Vous devrez spécifier les paramètres de modèle de call3 explicitement.

3

Vous devez spécifier lequel des trois tests dont vous avez besoin. Cela peut être accompli avec une distribution:

call3(a, static_cast<void (MyClass::*)(int, int, int)>(&MyClass::test), 1, 2, 3); 

Ce n'est pas vraiment propre. Il vaudrait probablement mieux donner des noms différents aux fonctions.

+0

Je reçois "impossible de déclarer le pointeur sur' 'void (&) (int, int, int)' '" – jcao219

+0

@ jcao219: Vous pouvez, mais cela a une certaine complexité en ce qui concerne la déduction des arguments.Voir ma réponse – Chubsdad

+0

@ jcao219: J'ai eu une faute de frappe, retirez le & dans la distribution (la réponse est éditée pour refléter cela). – JoshD

0

Je pense que le problème ici est que le compilateur n'est pas capable de résoudre la fonction test à laquelle vous faites référence.

Si supposons que vous avez des méthodes suivantes tho

void test(int, int, int); 
void test(int, int, const char *); 

maintenant si vous appelez test comme ça

test(1, 2, 3); 

3 peut être converti implicitement à const char *. Ainsi, le compilateur ne pourra pas résoudre entre les deux surcharges de la fonction test, et donc l'erreur de compilation.

La solution donnée par JoshD devrait résoudre votre problème

2

la raison en est que le compilateur a deux à choisir les surcharges dont chacun utilise trois paramètres . Notez que lors du processus de déduction d'argument, le compilateur déduit les paramètres de modèle participant des arguments d'appel de fonction en regardant indépendamment la paire paramètre/argument.

La déduction d'argument ne réussit que lorsque les paramètres du modèle sont déterminés sans ambiguïté en regardant chaque paire paramètre/argument.Cela signifie que tout en regardant votre deuxième couple paramètre/argument, il dépend (et ne peut pas) du fait que atype1, atype2 et atype3 sont chacun de type 'int', même si vous réarrangez les paramètres du modèle comme

template<class type, class ret, class atype1, class atype2, class atype3> 
ret call3(type *pClass, atype1 arg, atype2 arg2, atype3 arg3, ret(type::* funcptr)(atype1, atype2, atype3)) 
{ 
    //do some stuff here 
    return (pClass->*funcptr)(arg, arg2, arg3); 
} 

est ici la citation de la norme qui prend en charge ceci:

les contextes non déduits sont:

- le spécificateur imbriqué nom d'un type qui a été spécifié en utilisant un identifiant qualifié .

- Un argument de modèle non-type ou un groupement lié dans lequel une sous-expression fait référence à un paramètre de modèle.

- Un paramètre de modèle utilisé dans le type d'un paramètre de fonction de paramètres qui a un argument par défaut qui est utilisé dans l'appel pour lequel la déduction des arguments est fait.

- Un paramètre de fonction pour laquelle l'argument déduction ne peut être fait parce que le argument de la fonction associée est une fonction , ou un ensemble de fonctions surchargées (13.4), et un ou plusieurs de les conditions suivantes:

- plus d'une fonction correspondant à la fonction type de paramètre (résultant en une déduction ambiguë ) ou

- pas de fonction correspond au type de paramètre de fonction, ou

- l'ensemble des fonctions fournies comme un argument contient un ou plusieurs modèles de fonction .

maintenant la solution,

Je pense que la seule solution est que vous devrez spécifier explicitement les paramètres du modèle plutôt que de compter sur la déduction des arguments de modèle. Un petit réarrangement des paramètres du modèle aidera

template<class atype1, class atype2, class atype3, class type, class ret> 
ret call3(type *pClass, ret(type::* funcptr)(atype1, atype2, atype3), atype1 arg, atype2 arg2, atype3 arg3) 
{ 
    //do some stuff here 
    return (pClass->*funcptr)(arg, arg2, arg3); 
} 

int main(){ 
    MyClass *a = new MyClass(); 
    call3<int, int, int>(a, &MyClass::test, 1, 2, 3); 
} 
+0

call3 prend cinq paramètres. Vous devez les spécifier tous car il n'y a pas de paramètres par défaut. Donc, ajoutez 'MyClass' et' void' à cela. – JoshD