Pregunta la deducción / sustitución del argumento de la plantilla falló, al usar std :: function y std :: bind


Tengo un error de compilación al usar std :: function en una función de miembro con plantilla, el siguiente código es un ejemplo 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;
}

Y viene con el siguiente error de compilación:

testtemplate.cpp: En la función 'int main ()':

testtemplate.cpp: 29: 92: error: no hay función de coincidencia para llamar a   'Test :: setCallback (std :: _ Bind_helper) (int, int),   TestA, const std :: _ Placeholder <1> &, const   std :: _ Placeholder <2> &> :: type) '

testtemplate.cpp: 29: 92: nota: candidate es: testtemplate.cpp: 10: 7:   nota: plantilla vacía Prueba :: setCallback (std :: function)

testtemplate.cpp: 10: 7: nota: argumento de la plantilla   deducción / sustitución fallida:

testtemplate.cpp: 29: 92: nota: 'std :: _ Bind (TestA *, std :: _ Placeholder <1>,   std :: _ Placeholder <2>)> no se deriva de 'std :: function'

Estoy usando C ++ 11 y g ++ 4.7


18
2018-03-21 08:26


origen


Respuestas:


Para resolver el problema, deje las declaraciones separadas:

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

setCallback necesita saber el tipo de T y no puede deducirlo de f, así que dale un tipo

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

9
2018-03-21 08:44



Puede hacer que la deducción de tipos funcione con alguna 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 esta forma CALLBACK se puede determinar mirando el argumento. Puede tener problemas si bind no devuelve una función std :: sino algo que se puede convertir en uno. No estoy seguro.


0
2018-03-21 18:28