Сбой шаблона аргумента/подстановка при использовании std:: function и std:: bind

У меня есть ошибка компиляции при использовании std:: function в шаблонизированной функции-члена, следующий код - простой пример:

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

И придет следующая ошибка компиляции:

testtemplate.cpp: В функции 'int main():

testtemplate.cpp: 29: 92: ошибка: нет соответствующей функции для вызова 'Test:: setCallback (std:: _ Bind_helper) (int, int), TestA, const std:: _ Placeholder < 1 &, const станд:: _ Заполнитель < 2 > & > :: тип)

testtemplate.cpp: 29: 92: примечание: кандидат: testtemplate.cpp: 10: 7: note: шаблон void Test:: setCallback (std:: function)

testtemplate.cpp: 10: 7: note: аргумент шаблона вычет/замещение не удалось:

testtemplate.cpp: 29: 92: note: 'std:: _ Bind (TestA *, std:: _ Placeholder < 1 > , std:: _ Placeholder < 2 > ) > не выводится из 'std:: function

Я использую С++ 11 и g++ 4.7

Ответы

Ответ 1

Чтобы выяснить проблему, пусть отдельные инструкции:

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

setCallback должен знать тип T, и он не может вывести его из f, поэтому дайте ему тип

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

Ответ 2

Вы можете сделать операцию вывода типа с некоторым вариантом:

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

Таким образом, CALLBACK можно определить, просмотрев аргумент. Это может вызвать проблемы, если bind фактически не возвращает std:: function, а скорее что-то, что можно отличить как одно. Я не уверен.