Как назначить встроенную анонимную функцию указателю на функцию C ++ - PullRequest
0 голосов
/ 08 февраля 2020

Я запускаю немного кода на машине Arduino, которая использует C ++. Настройка (очень приблизительно), как показано ниже в основной функции. Пример довольно надуманный, и дизайн кода на самом деле не проходит проверку запаха, но это лучшее, что я могу сделать.

Есть сторонняя библиотека WiFi, которую я пытаюсь добавить "onDisconnect" зацепить Когда мой класс TaskRunner выполняется, я присоединяю функцию к этому хуку, чтобы, когда WiFi отключается, мой исполнитель задач получал уведомление.

Проблема в том, что я недостаточно хорошо знаю язык, чтобы назначить анонимную функцию, которая также поддерживает "isWifiConnected в области видимости. Я немного изучаю C ++ на лету, поэтому, пожалуйста, не стесняйтесь менять название вопроса, поскольку я даже не задаю правильный.

Обратите внимание, что я не могу искать анонимную функцию. Я пытаюсь обновить свойство isWifiConnected при вызове onDisconnect ().

#include <iostream>
using namespace std;


// A 3rd Party class
// https://github.com/Hieromon/AutoConnect/blob/master/src/AutoConnect.h
// https://github.com/Hieromon/AutoConnect/blob/master/src/AutoConnect.cpp
class AutoConnect {
     public:
        AutoConnect(){};

        // I add this to the class as a hook to be called at about
        // line 549 code block where AutoConnect calls disconnect code
        void (*onDisconnect)();
};



void onDisconnect(){
    cout << "Disconnecting!" << endl;
    cout << "But how to make isWifiConnected false?  I don't have access :/";
};


// My task runner 
class TaskRunner {

    public:
        bool isWifiConnected;
        AutoConnect *connector;

        TaskRunner(AutoConnect & connector){
           this->connector = & connector; 
        }

        void execute(){

            isWifiConnected = true;
            // run some WiFi connection code ...

            // assign the onDisconnect hook to be run when it disconnects
            connector -> onDisconnect = onDisconnect;

            // but how can I update "isWifiConnected" = false when the onDisconnect runs

            // In JavaScript, I could do
            /*
                connector -> onDisconnect = function(){
                    // variable stays in scope due to closure.
                    isWifiConnected = false;
                }
            */
        }
};




   int main() {
        cout<<"Running ..." << endl;

        // Instantiate my classes and inject WifiConnector into my task runner
        AutoConnect connector;
        TaskRunner runner = TaskRunner(connector);

        // Simulate an event loop for effect
        for(int i = 0; i < 10; i++){
            if(i == 0) runner.execute();
            // on some other condition, Wifi is disconnected
            if(i == 9)  connector.onDisconnect();
        }

        return 0;
    }

Любые идеи о том, как обновить переменную TaskRunner isWifiConnected? Я пробовал различные комбинации указателей но не могу понять это правильно.

1 Ответ

1 голос
/ 08 февраля 2020

Другие проблемы с кодом в стороне (см. Комментарии к вопросу):

Вы можете хранить лямбда в std::function:

Вместо void (*onDisconnect)(); объявить его std::function<void()> onDisconnect;. (требуется #include<functional>)

Тогда вы можете сохранить в нем лямбду захвата:

connector->onDisconnect = [this](){
    isWifiConnected = false;
};

Так как при этом сохраняется указатель на *this, вы должны убедиться, что TaskRunner объект переживает любой потенциальный вызов этой ловушки / лямбды. В противном случае ваша программа будет иметь неопределенное поведение .

В частности, в настоящее время TaskRunner объявляется после объекта AutoConnect в main, что означает, что последний будет уничтожен до AutoConnect и, следовательно, будет возможность вызова лямбды, когда TaskRunner уже уничтожен. Это особенно верно, если деструктор AutoConnect может вызвать лямбду. Так ли это или нет, я не знаю.

...