Search code examples
c++templatesoverloadingstd-functionfunction-signature

Why can't the compiler deduce to this function template?


We have a function that takes a function object as parameter. There are two overloads of the function, which differ in the function signature.

#include <functional>

template <typename T>
void foo(std::function<void(T)> bar)
{

}

template <typename T>
void foo(std::function<void(int, T)> bar)
{

}

int main()
{
    foo([](float number) {

    });
    return 0;
}

However, this code doesn't compile.

error C2784: 'void foo(std::function<void(int,T)>)' : could not deduce template argument for 'std::function<void(int,T)>' from 'main::<lambda_2b4e4413ec419a4ac179a0b64ebde221>' : see declaration of 'foo'
error C2784: 'void foo(std::function<void(T)>)' : could not deduce template argument for 'std::function<void(T)>' from 'main::<lambda_2b4e4413ec419a4ac179a0b64ebde221>' : see declaration of 'foo'

I think there is a problem with both the template itself and the overload. How can I provide two functions that match the above signatures?


Solution

  • Lambdas in C++ are instances of an anonymous class specifically created for each lambda object, this means that two lambdas with the same code are actually different objects.

    This also means that you can't pass lambdas around without using a template because there's no lambda type. Lambda is neither std::function ( and is not derived from it) nor a function pointer. They are unique types implementing application operator, i.e operator().

    You can do it using static_cast operator

    template <typename T>
    void foo(std::function<void(T)> bar)
    {
    }
    
    foo( static_cast< std::function<void(float)> >( [](float number){}));
    //or
    foo( std::function<void(float)>{ [](float){} } );