#c #arduino #atmega
#c #arduino #atmega
Вопрос:
Я пытаюсь вызвать функцию-член внешней библиотеки, которая принимает указатель на функцию в качестве параметра:
Timer::every(unsigned long period, void (*callback)(void));
Но, к сожалению, параметр, который я хочу передать, является функцией-членом:
void MyClass::the_method_i_want_to_pass(void);
Поскольку я программирую для ATmega под Arduino (AVR), поддержка c 11 ограничена. Мой первый подход вызывает ошибку типа:
void MyClass::the_method_i_want_to_pass() {...}
MyClass::MyClass() {
// constructor
Timer *timer = new Timer();
timer->every(500, [this](){this->the_method_i_want_to_pass();})
}
Вывод компилятора:
предупреждение: предупреждение: лямбда-выражения доступны только с -std= c 11 или -std= gnu 11 [включено по умолчанию]
ошибка: нет соответствующей функции для вызова ‘Timer:: every (int, MyClass::MyClass()::__lambda0)’
- Существуют ли другие / лучшие решения?
- Что касается моего текущего подхода: (Как) можно ли передать ссылку на лямбда-выражение, когда требуется указатель на функцию?
- Как я могу узнать, поддерживает ли Arduino / AVR эти лямбды (см. «Предупреждение»)?
Комментарии:
1. Поддерживает ли ваш компилятор
std::mem_fn
, хотя его c 112. Используя библиотеку StandardCplusplus, есть порт, который кажется похожим.
3. Этот вопрос не имеет смысла. Это все равно, что сказать: «Моя жена хочет, чтобы я принес домой помидоры. У меня есть коробка с гвоздями и буханка хлеба. 1. Есть ли какие-либо лучшие решения? 2. Как я могу угодить своей жене? 3. Как я могу найти жену, которая принимает гвозди и хлеб как помидоры? »
4. Я не понимаю вашей точки зрения @KerrekSB. На мой взгляд, это четко определенный вопрос об ограничении сторонней библиотеки.
5. Именно для этого и предназначено закрытие… инкапсуляция области / состояния в функцию. Каким будет ваше предложение?
Ответ №1:
Ваша основная проблема в том, что ваша Timer
библиотека написана плохо: она должна занимать void(*)(void*), void*
как минимум.
Без pvoid или эквивалента вы не можете передать какое-либо состояние, отличное от адреса в коде выполнения, для запуска процедуры. Поскольку метод также повторно this
использует указатель, вам не повезло.
Теперь, если ваш экземпляр MyClass
является одноэлементным, вы можете получить this
его откуда-нибудь еще.
В противном случае вам нужно создать собственное глобальное состояние, которое позволяет вам сопоставлять конкретный обратный вызов с некоторым состоянием. Если у вас ограниченное число MyClass
и другие потребители Timer
, вы можете иметь несколько фиксированных функций и сохранять их дополнительное состояние глобально.
Это все хак. То, что следует, хуже.
Напишите динамическую библиотеку с некоторым глобальным состоянием и void()
интерфейсом. Когда вы добавляете обратный вызов, дублируйте эту динамическую библиотеку, измените ее глобальное состояние во время выполнения, запишите ее как библиотеку с другим именем, загрузите ее и передайте чистую функцию обратного вызова вашему Timer
классу.
Или выполните эквивалентное значение без библиотеки, вручную написав машинный код и пометив страницы как выполнимые.
Все это плохие решения. Что приводит меня к хорошему: найдите лучшее Timer
. Если они испортили что-то настолько простое, остальная часть библиотеки, вероятно, тоже плоха.
Комментарии:
1. спасибо за ваш ответ! думаю, я начну с взлома, пока не смогу заменить его чем-то лучшим.