Search code examples
c++templateslambdacallbackfunction-pointers

Lambda cannot be passed to templated function which takes a function pointer


My Setup

I have these things setup,

  1. A struct
  2. A templated function pointer that takes that struct as parameter with T as return type
  3. A templated method invoker that takes the callback of the function pointer type with T as return type of the function pointer as well as the method.
// Setup

struct SomeParams
{
    const SomeType someData;
};

// Function Pointer
template<typename T>
using FuncCallback = T(__stdcall*)
    (
        SomeParams params
    );

// Method that takes the Function pointer
template<typename T>
T InvokerMethod(FuncCallback<T> callback);

Issue

When I try to call the InvokerMethod by passing a lambda expression the compiler cries.

auto myCallback = [](auto params)
    {
        return params.someData;
    };

SomeType data = ptr->InvokerMethod(myCallback); // Compile Error

Compilers tears show this error message:

Error E0304 - no instance of function template "InvokerMethod" matches the argument list

argument types are: (lambda [](auto params)->auto)

Works fine with same lambda as STATIC method

// .h
static SomeType GetData(const SomeParams params);

// .cpp
SomeType GetData(const SomeParams params)
{
    return params.someData;
}

SomeType data = ptr->InvokerMethod(GetData);

I want to know why there is no error when passing a static method but an error when passing a lambda.

I might be doing some silly thing as being new to cpp i might be overlooking some key knowledge around this. Please guide me, any help would be great!

I have tried making the lambda also static but doesn't work.


Solution

  • A lambda can only be converted to a function pointer if it does not capture, see Passing capturing lambda as function pointer.

    In OP's code,

    auto myCallback = [](auto params)
        {
            return params.someData;
        };
    

    The lambda has no capture, so it can decay to function pointer automatically.

    The reason why the code cannot compile is using auto in the lambda function. SomeType data = ptr->InvokerMethod(myCallback); // Compile Error cannot deduce the right type to instantiate the template for both lambda and InvokerMethod.

    Instead, try to explicitly give the type

    auto data = ptr->InvokerMethod<SomeType>(myCallback);
    

    See https://godbolt.org/z/95TP6rn6T for a live demo.