1

I'm writing a C++ code with the Arduino framework. It uses the avr-gcc compiler. I cannot use std::function. I set up a class with a callback and a simple example how I use it:

class GPI
{
public:
    typedef void(*GpiCallback)(bool value);

    GPI();
    void Begin(byte pin, GpiCallback callback);
    void Loop();

private:    
    GpiCallback _callback;
};

GPI::GPI() { }

void GPI::Begin(byte pin, GpiCallback callback)
{
    // do something
    _callback = callback;    
}

void GPI::Loop()
{
    // do something
    _callback(value);
}

in another class:

class Engine
{
public:
    Engine();
    void Init();
    // other members

private:
    GPI _gpi;
    bool _foo;
    // other members
};

void Engine::Init()
{
    _gpi.Begin(PIN_BUTTON, [](bool value)
    {
        Serial.print(F("[GPI] Button pressed"));            
    });
}

All this stuff works. Now I want to access, inside the lambda function, to the other members of my Engine class. Reading the documentations about lambdas I thought it should be enough to capture the this variable, i.e.:

_gpi.Begin(PIN_BUTTON, [this](bool value)
{
    Serial.print(F("[GPI] Button pressed"));
    _foo = true;
});

but I get a compiler error:

no conversion function exists from "lambda [](bool value)->void" to "GPI::GpiCallback"

I don't fully understand this message, actually. It reports the correct signature of the callback (even without the captured variable).

Why does capturing a variable lead to a wrong lambda signature?

Mark
  • 4,338
  • 7
  • 58
  • 120
  • 3
    Does this answer your question? [Passing capturing lambda as function pointer](https://stackoverflow.com/questions/28746744/passing-capturing-lambda-as-function-pointer) TL;DR: lambda cannot decay to a function pointer if it captures something. – pptaszni Nov 17 '22 at 13:10
  • @pptaszni I saw that question before but it seems related to a different error and the solutions says: "A lambda can only be converted to a function pointer if it does not capture" that is want I need to achieve. – Mark Nov 17 '22 at 13:12
  • 1
    @Mark You need to modify `GPI`. If you can't use something like `std::function`, then you need to implement some kind of subset of it yourself. At a minimum you can add a `void*` pointer to `GPI` that the user can initialize to some arbitrary value and add a `void*` parameter to the callback type, so that at this `void*` member can then be passed on to the callback where it is called. In your instance you would use this pointer to pass on `this`. – user17732522 Nov 17 '22 at 13:15
  • 2
    Yeah understood, but it is not possible. Lambda that captures simply cannot be casted to a function pointer. You need to look for workarounds, like some hacky C-style stuff `typedef void(*GpiCallback)(bool value, void* userData);` and then `reinterpret_cast(userData)` inside lambda. – pptaszni Nov 17 '22 at 13:16
  • Got it. I'm going to try this approach even it's a little cumbersome for me... – Mark Nov 17 '22 at 13:18
  • 2
    @pptaszni `static_cast` will be enough and is harder to make mistakes with. – user17732522 Nov 17 '22 at 13:19

0 Answers0