Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.102.178] |
|
Сообщ.
#1
,
|
|
|
Здравствуйте)
Собственно, сам вопрос: подскажите пожалуйста, как мне обьявить делегат в сишном стиле так, чтобы я мог пихать на его место плюсовые лямбды, которые умеют работать с внешними переменными? Условие: нельзя использовать STL, в том числе, нельзя использовать functional Поясню подробнее: Вот пример того что я хочу сделать: typedef void(*Delegate)(); void test(Delegate action) { action(); } int main() { int a = 0; auto func = []() // В этом место могло быть [=] или [*] { a++; }; test(func); } Однако, очевидно что в таком виде переменная a недоступна лямбде, а в случае если я меняю тело [], получается что лямбда перестаёт соответствовать объявлению делегата Delegate. Подумываю попробовать сделать Delegate через templates, чтобы можно было сделать хотябы так: Delegate<int> func = [](&a) { a++; } Но, не уверен что получится реализовать чисто и удобно, поэтому задаю вопрос, быть может, есть более тривиальное решение, которое я в упор не вижу... Прошу не ругаться по поводу черезжопности подхода к реализации |
Сообщ.
#2
,
|
|
|
Обертку сделай, по другому никак судя по всему.
Добавлено Как то так: https://ideone.com/CYsIjc #include <iostream> using namespace std; typedef void(*Delegate)(); void test(Delegate action) { action(); } int main() { int a = 0; auto func = [&a]() // В этом место могло быть [=] или [*] { ++a; std::cout << "func: " << a ; }; static auto staticFn = func; Delegate ptr = []( ) { return staticFn(); }; test(ptr); return 0; } Добавлено Ну и к слову, я уже вроде задавал такой вопрос, можешь еще тут посмотреть варианты решения: Cконвертировать замыкание со списком захвата в указатель на функцию С++14 |
Сообщ.
#3
,
|
|
|
Цитата Wound @ Cконвертировать замыкание со списком захвата в указатель на функцию С++14 Интересно ещё то, что автор хочет сделать то же самое что мне и нужно Ух... выглядит, конечно, очень неудобно... Спасибо за идею, думаю, можно придумать что нибудь, что будет обарачивать подобные лямбды с захватом в статик как у вас) Ещё поковыряю |
Сообщ.
#4
,
|
|
|
Цитата VisualProg @ Как наковыряете что-нибудь - не сочтите за труд, выложите здесь. Тоже может понадобиться, запишу на корочку. Ещё поковыряю |
Сообщ.
#5
,
|
|
|
Цитата VisualProg @ Интересно ещё то, что автор хочет сделать то же самое что мне и нужно В принципе автор там сделал так, как ему ответили в последнем посту. Вроде работало. |
Сообщ.
#6
,
|
|
|
Ну, первое что пришло в голову, сделать прямую обёртку, по стопам Wound:
#define MakeLambdaAction(name, x) \ auto _tmp##name = x; \ static auto _static##name = _tmp##name; \ auto name = []() { _static##name(); } Собственно, в первом аргументе указывается имя лямбды, во втором аргументе - тело. typedef void(*Delegate)(); void test(Delegate action) { action(); } int main() { int counter = 0; MakeLambdaAction(ptr, [&counter]() { std::cout << "timer tick...\n"; counter++; }); test(ptr); } 1. Я надеюсь что этот код никто не увидит 2. Я искренне надеюсь что мне не придётся использовать его в таком виде, хотя, очевидно, что это 100% решает мою проблему... |
Сообщ.
#7
,
|
|
|
Без захвата локальные переменные никак не обработать. Ссылки на них по-любому придётся как-то хранить, и шаблоны тут тоже не помогут, т.к. такие ссылки не могут быть разрешены в компайл-тайм. Единственный возможный вариант – зафиксировать ссылку на неё в ран-тайм. А возможно это только посредством её инициализации в статик сторадж после определения локальной переменной.
|
Сообщ.
#8
,
|
|
|
Цитата VisualProg @ очевидно, что это 100% решает мою проблему... А в чем заключается исходная проблема? Если вы захватываете что-то в лямбду, то вы теряете совместимость с указателем на функцию. И это естественно. В Си классически используется другой подход. В изначальный callback добавляют void*-аргумент и позволяют устанавливать и callback и указатель на произвольные данные, который и будет передан в callback при вызове. Что нужно-то? |
Сообщ.
#9
,
|
|
|
Цитата D_KEY @ А в чем заключается исходная проблема? Есть один поток в котором выполняется бесконечный цикл, в его рамках надо формировать и выполнять множество несвязанных между собой операций. Каждая операция должна выполняться с определённым приоритетом, и каждая операция должна выполняться не чаще определённого интервала времени. В классическом случае, я вижу такое решение: 1. Под конкретную операцию завожу переменную хранящую время последнего запуска (например, в миллисекундах) 2. Каждую итерацию бесконечного цикла смотрю сколько времени прошло с момента предыдущего выполнения операции 3. Если операция не выполнялась достаточно долго (наш интервал и больше), ставлю её на выполнение. Вот пример реализации одной такой операции auto lastTimestamp = Time::getTimestamp(); for(;;) { auto timestamp = Time::getTimestamp(); if(timestamp - lastTimestamp >= INTERVAL) { doSomething(); lastTimestamp = timestamp; } } Теперь добавим вторую операцию в этот цикл: auto lastTimestampOperation1 = 0; auto lastTimestampOperation2 = 0; for(;;) { auto timestamp = Time::getTimestamp(); if(timestamp - lastTimestampOperation1 >= INTERVAL1) { doSomething1(); lastTimestampOperation1 = timestamp; } if(timestamp - lastTimestampOperation2 >= INTERVAL2) { doSomething2(); lastTimestampOperation2 = timestamp; } } Как вы уже поняли, делать так не интересно. Я создаю класс, который скрывает всю эту тягомотину с запоминанием времени последнего выполнения, однако, ему необходимо знать что именно ему делегировали выполнять, с чем и возникла проблема, которую я описал в вопросе. Вот как у меня теперь наращиваются операции: Time::Timer operation1(INTERVAL1, doSomething1()); Time::Timer operation2(INTERVAL2, doSomething2()); for(;;) { operation1.update(); operation2.update(); } Ну, или совсем красиво: List<Time::TimedObject> operations( { Time::Timer(INTERVAL1, doSomething1()), // Добавление операций Time::Timer(INTERVAL2, doSomething2()), // ... }); for(;;) { operations.update(); } Добавлено Так вот, я столкнулся с тем, что не всегда удобно формировать свой объект таймера с указателем на реальный метод, начал копать лямбды, и упёрся в вышеописанное... |
Сообщ.
#10
,
|
|
|
Язык: c++
Стандарт: c++11 Железка: Arduino (целевая - Nano) Из библиотек только сама голая ардуинная приблуда (там чистый c98) Так что, говорим о c++11 без STL. Всё остальное допиливается руками, либо частично берутся готовые фрагменты реализаций из STL (если это возможно) Не знаю чем это вам поможет... |