Lambda function not capturing by value

Status
Not open for further replies.

Edward

Well-known member
Hi all,

what I'm trying to do is create a lamba function to use as an interrupt, to create a class that will automatically generate it's interrupt functions. The end use is for an encoder class, because each object will need four interrupts and I don't want to hardcode the number of encoders/interrupts etc.

Now what I'd like to do is create an array of pointers to all the encoders in use, and index from that array to create each interrupt. From my understanding I should be able to capture by value, not reference, any variables used in the lambda function. I can do all of this except the capture by value part. I've been testing the idea on a much simpler LED class and timerOne (because It provides quick visual feedback). The code

Code:
#include <TimerOne.h>


int numberOfLeds =0;

class LED{
  public:
  const byte _ledPin;

  LED(const byte pin) : _ledPin(pin) {
    numberOfLeds++;
  }
  void toggle() {digitalWrite(_ledPin, !(digitalRead(_ledPin)));}
};



LED led1(13);
LED led2(14);
void setup(void)
{
  pinMode(14, OUTPUT); // I've hard coded this bit for now
  pinMode(13, OUTPUT);
  static LED ** pointers = new LED * [numberOfLeds];  // this array has to be static to work atm
  pointers[1] = &led1; 
  pointers[0] = &led2;
  static int count = 1;

  Timer1.initialize(150000);
  Timer1.attachInterrupt([=](){pointers[count]->toggle();}); // blinkLED to run every 0.15 seconds
  //count = 0;                    // uncomment This line and led2 will blink instead
  Serial.begin(9600);
}

void loop(void)
{
  delay(100);
}

what I'm finding is that the code compiles and runs, but the led will change after the creation of the lamba if count is changed. Count has to be static, as well as the array of pointers - meaning the lambda is capturing the values by reference not by value; even though I'm using "[=]" which should make it capture by value. Can anyone tell me how to force it to capture by value?

thanks
 
What you want simply doesn't work. You need a plain function pointer for "attachInterrupt()". Only lambdas without captures can decay to a function pointer, lambdas with captures can't (the captured stuff has to be stored - function pointers don't have storage space).

The reason your code compiles is that you are not capturing anything, you are using the variables directly.
 
I would use a static template class:

Code:
template<uint8_t pin1, uint8_t pin2>
class Encoder {
private:
    Encoder();
public:
    static void start() {
        pinMode(pin1, INPUT_PULLUP);
        pinMode(pin2, INPUT_PULLUP);

        attachInterrupt(pin1, isr, CHANGE);
        attachInterrupt(pin2, isr, CHANGE);
        
        //...
    }
    //...
    static uint8_t state;
    static uint32_t counter;
    
private:
    static void isr() {
        // ...
    }
};


using encoder1 = Encoder<3, 4>;
using encoder2 = Encoder<7, 8>;

void setup() {
    encoder1::start();
    encoder2::start();
    // ...
}
 
Status
Not open for further replies.
Back
Top