web-dev-qa-db-fra.com

échec de la déduction / substitution des arguments de modèle, lors de l'utilisation de std :: function et std :: bind

J'ai une erreur de compilation lors de l'utilisation de std :: function dans une fonction membre basée sur un modèle, le code suivant est un exemple simple:

#include <functional>
#include <memory>
using std::function;
using std::bind;
using std::shared_ptr;

class Test {
public:
     template <typename T>
     void setCallback(function<void (T, int)> cb); 
};

template <typename T>
void Test::setCallback(function<void (T, int)> cb)
{
    // do nothing
}

class TestA {
public:
    void testa(int a, int b) {   }
};


int main()
{
    TestA testA;
    Test test;
    test.setCallback(bind(&TestA::testa, &testA, std::placeholders::_1, std::placeholders::_2));
    return 0;
}

Et venez avec l'erreur de compilation suivante:

testtemplate.cpp: Dans la fonction ‘int main ()’:

testtemplate.cpp: 29: 92: erreur: aucune fonction correspondante pour l'appel à 'Test :: setCallback (std :: _ Bind_helper) (int, int), TestA, const std :: _ Placeholder <1> &, const std :: _ Placeholder <2> &> :: type) '

testtemplate.cpp: 29: 92: note: le candidat est: testtemplate.cpp: 10: 7: note: template void Test :: setCallback (std :: function)

testtemplate.cpp: 10: 7: remarque: la déduction/substitution d'argument de modèle a échoué:

testtemplate.cpp: 29: 92: remarque: "std :: _ Bind (TestA *, std :: _ Placeholder <1>, std :: _ Placeholder <2>)>" n'est pas dérivé de "std :: function"

J'utilise C++ 11 et g ++ 4.7

22
haipeng31

Pour comprendre le problème, séparez les instructions:

auto f = bind(&TestA::testa, &testA, _1, _2); // OK
test.setCallback(f);                          // <<--- Error is here

setCallback a besoin de connaître le type de T et il ne peut pas le déduire de f, alors donnez-lui un type

test.setCallback<TYPE>(f); // TYPE: int, float, a class, ...
11
deepmax

Vous pouvez faire fonctionner la déduction de type avec une variante de:

template<typename CALLBACK>
void setCallback(CALLBACK cb) {
  typedef CALLBACK::first_argument_type T;
  static_assert(is_same_type<CALLBACK,function<void(T,int)>>::value);
  ...
}

De cette façon, CALLBACK peut être déterminé en regardant l'argument. Cela pourrait avoir des ennuis si bind ne retourne pas réellement une fonction std :: mais plutôt quelque chose qui peut être converti en une seule. Je ne suis pas sûr.

0
dspeyer