template argument deduction/substitution failed, when using std::function and std::bind

49,899

Solution 1

To figure out the problem let separate statements:

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

setCallback needs to know type of T and it can't deduce it from f, so give it a type

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

Solution 2

You can make type deduction work with some variant of:

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

This way CALLBACK can be determined by looking at the argument. It might get into trouble if bind doesn't actually return a std::function but rather something that can be cast as one. I'm not sure.

Share:
49,899
haipeng31
Author by

haipeng31

Updated on March 22, 2020

Comments

  • haipeng31
    haipeng31 about 4 years

    I have a compile error when using std::function in a templated member function, the following code is a simple example:

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

    And come with the following compile error:

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

    testtemplate.cpp:29:92: error: no matching function for call to ‘Test::setCallback(std::_Bind_helper)(int, int), TestA, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type)’

    testtemplate.cpp:29:92: note: candidate is: testtemplate.cpp:10:7: note: template void Test::setCallback(std::function)

    testtemplate.cpp:10:7: note: template argument deduction/substitution failed:

    testtemplate.cpp:29:92: note: ‘std::_Bind(TestA*, std::_Placeholder<1>, std::_Placeholder<2>)>’ is not derived from ‘std::function’

    I'm using C++11 and g++ 4.7