如何定义一个 lambda 函数以便能够捕获类的“this”指针?

How to define a lambda function to be able to capture the 'this' pointer of a class?

提问人:Dr.Random 提问时间:10/26/2022 最后编辑:Dr.Random 更新时间:10/26/2022 访问量:128

问:

我有一个跟踪时间的时间类。

我希望我的其他类能够在日期发生变化时注册回调函数。

我有这个工作片段:

#define MAX_CB_CHANGE_FUNCTIONS 50
typedef void (*dayChangeFunc)(int prevDay,int nowDay);

class TimeSystem {
    private:
        // array for the function pointers.
        dayChangeFunc dayChangeFunctions[MAX_CB_CHANGE_FUNCTIONS];
        // emit function if the day changes.
        void emitDayChange(int prev, int now);
    public:
        void regDayChange(dayChangeFunc);
};


/*
*   Registering a day change function.
*   Maximum function pointer count is MAX_CB_CHANGE_FUNCTIONS ( see timeSys.h )
*/
void TimeSystem::regDayChange(void (*dayChangeFunc)(int prevDay,int nowDay)){
    if( currDayCbIndex >= MAX_CB_CHANGE_FUNCTIONS ){
        if(isDebugOn){
            debug.print(DEBUG_WARN,"[Time_sys] - Can not register an other day change function.\n");
            return;
        }
    }
    dayChangeFunctions[currDayCbIndex] = dayChangeFunc;
    currDayCbIndex++;
}

/*
*   Emitting day change to every registered function.
*/
void TimeSystem::emitDayChange(int prev, int now){
    // Preventing change on initialization.
    if( prev == 0 ){ return; }
    for (size_t i = 0; i < MAX_CB_CHANGE_FUNCTIONS; i++){
        if(dayChangeFunctions[i]){
            dayChangeFunctions[i](prev,now);
        }
    }
}

这是有效的,其他 calsses 可以像这样使用它:

timeSys.regDayChange([](int prevDay,int nowDay){
    Serial.printf("Day changed from prev: %d to now: %d\n",prevDay,nowDay);
});

现在我想在 lambda 中捕获“this”指针,以便能够调用类的某些内部函数。

timeSys.regDayChange([this](int prevDay,int nowDay){
    callSomeInternalFunction();
});

我得到的错误:

no suitable conversion function from "lambda [](int prevDay, int nowDay)->void" to "dayChangeFunc"

如何定义我的 lambda 以便能够捕获“this”指针?

******** 编辑:已解决 ********

以下是修改:

我必须像这样定义我的 lambda 函数类型:

using dayChangeFunc = std::function<void(int, int)>;

定义函数指针寄存器函数,如下所示:

void regDayChange(dayChangeFunc cb);

并像这样重写声明:

/*
*   Registering a day change function.
*   Maximum function pointer count is MAX_CB_CHANGE_FUNCTIONS ( see timeSys.h )
*/
void TimeSystem::regDayChange( dayChangeFunc cb ){
    if( currDayCbIndex >= MAX_CB_CHANGE_FUNCTIONS ){
        if(isDebugOn){
            debug.print(DEBUG_WARN,"[Time_sys] - Can not register an other day change function.\n");
            return;
        }
    }
    dayChangeFunctions[currDayCbIndex] = cb;
    currDayCbIndex++;
}

现在我可以在任何类中使用它,如下所示:

class SampleClass(){
  private:
     int exampleCounter = 0;
  public:
    void init(){
      TimeSystem timeSys;
      timeSys.regDayChange([this](int prevDay,int nowDay){
        Serial.printf("Day changed from prev: %d to now: %d\n",prevDay,nowDay);
        exampleCounter++;
      });
    }
}
C++ lambda 这个 捕获 arduino-esp32

评论

0赞 local-ninja 10/26/2022
您的 c++ 标准是什么?
0赞 Dr.Random 10/26/2022
PlatformIO 标准 AFAIK 是 C++11
0赞 molbdnilo 10/26/2022
将回调类型更改为 。std::function<void(int, int)>
0赞 Dr.Random 10/26/2022
喜欢这个?typedef std::function<void(int, int)>;
0赞 Dr.Random 10/26/2022
我收到以下错误:声明没有声明任何内容 [-fpermissive]

答:

0赞 lorro 10/26/2022 #1

捕获任何内容的 lambda 函数不能转换为函数指针。您需要手动传递指针,或者需要有一个函数“池”,每个函数全局存储当前指针。this

评论

0赞 Dr.Random 10/26/2022
我可以以某种方式使用它的std::函数吗?
0赞 lorro 10/26/2022
@Dr.随机 否,除非您在回调中也更改了它。 还需要一个指针。你所要求的东西在 c++ 中根本行不通。std::function
0赞 molbdnilo 10/26/2022
@lorro -capturing lambda 需要什么指针?this
0赞 Dr.Random 10/26/2022
调用它的整个类。
0赞 Dr.Random 10/26/2022
我正在各种类中注册一个回调函数,并想在回调中做与类相关的事情。
2赞 molbdnilo 10/26/2022 #2

将回调类型更改为std::function<void(int, int)>

using dayChangeFunc = std::function<void(int, int)>;

typedef std::function<void(int, int)> dayChangeFunc;

并更改功能原型,

void TimeSystem::regDayChange(dayChangeFunc func).

(如果您始终如一地使用类型别名,则无需更改原型,只需更改别名本身即可。如果使用类型别名,则它们最有用。

评论

0赞 Dr.Random 10/26/2022
非常感谢您的回答!您推荐使用关键字还是 typedef 关键字?
0赞 molbdnilo 10/26/2022
用。现在几乎没有人使用,甚至有些情况你不能使用。保持一致是一件好事。usingtypedef
0赞 Dr.Random 10/26/2022
谢谢!我会读到更多使用的信息。