Проблема в том, что функция enable_irq
ожидает типизированного указателя функции типа void (*ExtiHandler)()
, а не лямбда-функции .
Это означает, что здесь
pin.enable_irq([this]() { this->button_pressed(); });
вы пытаетесь сохранить лямбда-функцию (с захватом экземпляра) в типизированном указателе функции .Вы могли бы преобразовать лямбду в указатель на функцию (легко), если бы она была лямбда без захвата.
См. [expr.prim.lambda.closure] (сек. 7)
Тип закрытиядля неуниверсального лямбда-выражения с без лямбда-захвата , чьи ограничения (если таковые имеются) выполнены, имеет функцию преобразования в указатель на функцию с языковой связью C ++, имеющей тот же параметр ивозвращать типы в качестве оператора вызова функции типа замыкания.
Поскольку лямбда-выражения не являются просто обычными функциями , и для его захвата необходимо сохранить состояние , вы не можетенайдите любое простое или традиционное решение, чтобы назначить их указателям на функции.
Решение - 1
Самое простое решение - использовать std::function
вместо этого, заплатив некоторые накладные расходы на стирание типа .Это означает, что в вашем коде просто нужно изменить
typedef void(*ExtiHandler)();
на
typedef std::function<void()> ExtiHandler;
// or
// using ExtiHandler = std::function<void()>;
Решение - 2
Можно ли это сделатьбез использования STL?
Да .Проведя небольшое исследование по этой теме, я нашел решение для определения черт типа для хранения лямбд с закрытием в эквивалентном типизированном указателе функции.
#include <iostream>
template<typename Lambda> struct convert_lambda : convert_lambda<decltype(&Lambda::operator())> {};
template<typename Lambda, typename ReType, typename... Args>
struct convert_lambda<ReType(Lambda::*)(Args...) const>
{
using funPtr = ReType(*)(Args...);
static funPtr make_function_ptr(const Lambda& t)
{
static const Lambda& lmda = t;
return [](Args... args) { return lmda(args...); };
}
};
template<typename Lambda> using convert_lambda_t = typename convert_lambda<Lambda>::funPtr;
template<typename Lambda> constexpr convert_lambda_t<Lambda> make_function_ptr(const Lambda& t)
{
return convert_lambda<Lambda>::make_function_ptr(t);
}
Использование: СМОТРИТЕ ПРИМЕР ЖИВЫХ
Теперь вы можете просто продолжить с Gpio
и Button
классы, ничего не меняя .:
pin.enable_irq(make_function_ptr([this]() { this->button_pressed(); }));
// or
// pin.enable_irq(make_function_ptr([&]() { this->button_pressed();}));
Или с аргументами.Например
int aa = 4;
auto lmda = [&aa](const int a, const float f) { std::cout << a * aa * f << std::endl; };
void(*fPtrTest)(const int, const float) = make_function_ptr(lmda);
fPtrTest(1, 2.0f);
Недостатки: Решение - 2:
равно нет способен распознавать необязательную последовательность спецификаторов . (Т. Е. mutable
, constexpr
)
не пересылки пакета параметров к чертам.то есть следующее невозможно:
return [](Args&&... args) { return lmda(std::forward<Args>(args)...); };