Передача функции в качестве аргумента с захватом, какой тип объявить в функции?

c++

Возможно, это простое разрешение, но не удается найти правильную комбинацию.

Я пытаюсь настроить функцию (setupScreen), чтобы она принимала в качестве аргумента функцию для фактической настройки:

void ScreenHelpers::setupScreen(void (*setupFunc)(ThinkInk_290_Tricolor_Z10*)){
    ScreenHelpers::waitTilCanRefreshScreen();

    (* setupFunc)(&display_two);

    lastUpdateTime = millis();
}
//...
void ScreenHelpers::displayErrorMessage(const String message){
    const char* text = message.c_str();
    ScreenHelpers::setupScreen([text](ThinkInk_290_Tricolor_Z10* screen) {
        screen->clearBuffer();
        ScreenHelpers::simpleDisplayText(
            screen,
            text,
            EPD_RED
        );
     });
}

Это работает, пока я не добавил [text] для захвата переменной text в лямбда-выражении, где это привело к следующему:

ScreenHelpers.cpp: In static member function 'static void ScreenHelpers::displayErrorMessage(String)':
ScreenHelpers.cpp:45:4: error: no matching function for call to 'ScreenHelpers::setupScreen(ScreenHelpers::displayErrorMessage(String)::<lambda(ThinkInk_290_Tricolor_Z10*)>)'
   });
    ^
ScreenHelpers.cpp:21:6: note: candidate: 'static void ScreenHelpers::setupScreen(void (*)(ThinkInk_290_Tricolor_Z10*))'
 void ScreenHelpers::setupScreen(void (*setupFunc)(ThinkInk_290_Tricolor_Z10*)){
      ^~~~~~~~~~~~~

Как должно выглядеть объявление моей функции, чтобы принять это?

, 👍1

Обсуждение

Это не конкретный вопрос Arduino, это проблема чистого С++. Пожалуйста, спросите об этом на [so], если вы все еще не знаете, как это сделать, после проведения необходимых исследований., @the busybee

Я должен не согласиться, C++ Arduino — странное подмножество языка. Я бы сказал, что разумно обратиться к местам, специфичным для Arduino, для расширенных языковых функций., @Snappawapa

Компилятор, используемый Arduino, представляет собой стандартный компилятор GNU C++, предназначенный для процессоров AVR или ARM. Таким образом, он не ограничен **языком**, и мы программируем на стандартном C++. Но прилагаемые **библиотеки C++** могут быть неполными, например, <functional> может отсутствовать, конечно. -- Так что это помогло, если бы вы упомянули свою конкретную цель Arduino., @the busybee


1 ответ


Лучший ответ:

2

ScreenHelpers::setupScreen() ожидает, что его аргумент будет простым функция. Захватывающая лямбда — это не простая функция: это скорее функтор, то есть объект, который можно вызывать как функцию.

Стандартный способ передачи такой лямбда-выражения в C++ — объявить параметр должен иметь тип std::function:

#include <functional>

void ScreenHelpers::setupScreen(std::function<void(ThinkInk_290_Tricolor_Z10*)> setupFunc) {
    ...
}

Это может работать или не работать в зависимости от используемой платы Arduino. Платы на основе AVR основаны на библиотеке C, которая лишь минимально поддерживает C++. Вы не можете использовать <functional> на этих платах. Если вы используете один из этих плат, ваши варианты:

  1. Попробуйте найти реализацию C++ STL для плат на базе AVR. Я видел по крайней мере один, плавающий в Сети.

  2. Используйте стандартную идиому C для определения обратного вызова с void* параметр:

void ScreenHelpers::setupScreen(
      void (*setupFunc)(ThinkInk_290_Tricolor_Z10*, void*),
      void *callback_data) {
   setupFunc(&display_two, callback_data);
   //...
}

// elsewhere:
ScreenHelpers::setupScreen([](ThinkInk_290_Tricolor_Z10 *screen, void *data) {
   const char *text = (const char *) data;
   // ...
}, (void *) text);
,

Спасибо! Похоже, моя плата поддерживает лямбда-выражения, что упрощает задачу! Второй вариант тоже пришел мне в голову, я тоже подумал, может быть, сделать параметр * data varargs., @Snappawapa