Лямбда как параметр в функцию
От: koenjihyakkei Россия  
Дата: 29.07.15 12:55
Оценка:
Как передать лямбду в функцию не используя std::function?
Re: Лямбда как параметр в функцию
От: _NN_ www.nemerleweb.com
Дата: 29.07.15 12:59
Оценка: 2 (1) +1
Здравствуйте, koenjihyakkei, Вы писали:

K>Как передать лямбду в функцию не используя std::function?


Шаблоном:
template<typename T> void a(T f) { f(1, 2, 3); }

int main()
{
 a([](int a,int b,int c) { return a+b+c; }); 
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Лямбда как параметр в функцию
От: koenjihyakkei Россия  
Дата: 29.07.15 13:50
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Шаблоном:

_NN>
_NN>template<typename T> void a(T f) { f(1, 2, 3); }

_NN>int main()
_NN>{
_NN> a([](int a,int b,int c) { return a+b+c; }); 
_NN>} 
_NN>


Спасибо, правда минус в том, что функция довольно большая и тащить ее в хедер из-за шаблона не хочется.
Жалко, что лямбда не может передаваться как указатель на функцию, надеялся тут есть какой-то способ схитрить.
Re[3]: Лямбда как параметр в функцию
От: watchmaker  
Дата: 29.07.15 14:07
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Спасибо, правда минус в том, что функция довольно большая и тащить ее в хедер из-за шаблона не хочется.

K>Жалко, что лямбда не может передаваться как указатель на функцию
Лямбда без захвата — может. Не твой случай?

K> надеялся тут есть какой-то способ схитрить.

Способы-то есть. Например, можно использовать динамическую генерацию прокси-функций. Тогда в библиотечную функцию передаётся уникальный указатель на прокси, а сама прокси-функция уже может передавать управление на лямбду.
Впрочем эта (и аналогичные хитрости) оправданы только в самых крайних случаях — когда интерфейс вообще нет возможности поменять (например, из-за отсутствия исходников). В нормальном же режиме лучше всё-таки использовать std::function. Ну или хотя бы пару указателей (на код функции и на контекст, как это, собственно, и делается повсеместно в С и различных API).
Re[4]: Лямбда как параметр в функцию
От: koenjihyakkei Россия  
Дата: 29.07.15 14:39
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Лямбда без захвата — может. Не твой случай?


Не мой, в захвате вся соль.

W>Способы-то есть. Например, можно использовать динамическую генерацию прокси-функций. Тогда в библиотечную функцию передаётся уникальный указатель на прокси, а сама прокси-функция уже может передавать управление на лямбду.

W>Впрочем эта (и аналогичные хитрости) оправданы только в самых крайних случаях — когда интерфейс вообще нет возможности поменять (например, из-за отсутствия исходников). В нормальном же режиме лучше всё-таки использовать std::function. Ну или хотя бы пару указателей (на код функции и на контекст, как это, собственно, и делается повсеместно в С и различных API).
Ну это уж слишком замороченные хитрости

Пока сделал через std::function. Просто код в какой-то мере платформозависимый и не факт, что в продакшене std вообще будет. Но пока покатит, дальше видно будет)
Re[5]: Лямбда как параметр в функцию
От: Went  
Дата: 29.07.15 15:03
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:
K>Пока сделал через std::function. Просто код в какой-то мере платформозависимый и не факт, что в продакшене std вообще будет. Но пока покатит, дальше видно будет)
Ну, свой костыль никогда не поздно будет дописать.
Re[3]: Лямбда как параметр в функцию
От: _NN_ www.nemerleweb.com
Дата: 29.07.15 17:36
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Здравствуйте, _NN_, Вы писали:


_NN>>Шаблоном:

_NN>>
_NN>>template<typename T> void a(T f) { f(1, 2, 3); }

_NN>>int main()
_NN>>{
_NN>> a([](int a,int b,int c) { return a+b+c; }); 
_NN>>} 
_NN>>


K>Спасибо, правда минус в том, что функция довольно большая и тащить ее в хедер из-за шаблона не хочется.

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

K>Жалко, что лямбда не может передаваться как указатель на функцию, надеялся тут есть какой-то способ схитрить.

Можно если нет захвата контекста.
А вообще давно пора иметь такой механизм, будем надеется , что в будущем такое добавят.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Лямбда как параметр в функцию
От: enji  
Дата: 30.07.15 05:01
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>А какая разница какой размер функции ?

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

_NN>А вообще давно пора иметь такой механизм, будем надеется , что в будущем такое добавят.


Что ты имеешь в виду? std::function и есть такой механизм...
Re[5]: Лямбда как параметр в функцию
От: _NN_ www.nemerleweb.com
Дата: 30.07.15 06:22
Оценка:
Здравствуйте, enji, Вы писали:

E>Здравствуйте, _NN_, Вы писали:


_NN>>А какая разница какой размер функции ?

_NN>>Единственная проблема заголовочного файла это включение дополнительных зависимостей.
_NN>>Если их нет, то и проблемы нет в принципе.
E>Проблема еще и в раздувании объема программы — будет создано по одной копии функции на каждую точку вызова (подозреваю все лямбды имеют разный тип)
Да ладно. Неужели вы считаете компилятор настолько тупым ?
Ну и даже размер будет больше это не так страшно как рисуется.
Сомневаюсь, что у вас получится накинуть мегабайт на каждое воплощение шаблона.

Ну и std::function тоже не так страшен как его рисуют.
Там как минимум есть оптимизация с использованием стека для простых случаев.

_NN>>А вообще давно пора иметь такой механизм, будем надеется , что в будущем такое добавят.


E>Что ты имеешь в виду? std::function и есть такой механизм...

Не, именно генерацию кода и получение обычного указателя на функцию в стиле C.
Где-то пробегала ссылка на предложение включить это в стандарт.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Лямбда как параметр в функцию
От: Кодт Россия  
Дата: 30.07.15 10:25
Оценка:
Здравствуйте, koenjihyakkei, Вы писали:

K>Как передать лямбду в функцию не используя std::function?


Сделать легковесную санку
// это будем передавать в функцию
struct IFun {
  virtual int operator()(int x, int y, int z) const = 0;
};

// это та самая функция
extern void run(IFun const& f);

// сделаем обёртку над произвольной лямбдой
template<class F> struct FunThunk : IFun {
  F const& f; // по ссылке - чтоб лишнего не копировать (всё равно временный объект)
  FunThunk(F const& f) : f(f) {}

  int operator()(int x, int y, int z) const override {
    return f(x,y,z);
  }
};
template<class F> auto make_fun_thunk(F const& f) -> FunThunk<F> {
  return FunThunk<F>(f);
}

// вызовем
void go(int p) {
  auto lambda = [&](int x, int y, int z) { return (p++) + x + y + z; };

  run(make_fun_thunk(lambda));
}


Вот как-то так. Корявенько и многословно, зато эффективно.
Перекуём баги на фичи!
Re[6]: Лямбда как параметр в функцию
От: enji  
Дата: 30.07.15 11:21
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Да ладно. Неужели вы считаете компилятор настолько тупым ?

компилятор обрабатывает по одной единице трансляции за раз. Реализации будут различаться, линкер тут не поможет. LTO не всегда включено / нормально работает

_NN>Ну и даже размер будет больше это не так страшно как рисуется.

_NN>Сомневаюсь, что у вас получится накинуть мегабайт на каждое воплощение шаблона.
Разные же приложения есть. У меня кое-где память программ 120Кб

E>>Что ты имеешь в виду? std::function и есть такой механизм...

_NN>Не, именно генерацию кода и получение обычного указателя на функцию в стиле C.
Не понял идеи, можно пример? Как можно получить обычный указатель, имея замыкание?

typedef void(*P)();

void g(P);

void f(int a) {
  P p = [a]{ std::cout<<a; }; // ???
  g(p);
}
Re[3]: Лямбда как параметр в функцию
От: dad  
Дата: 30.07.15 11:29
Оценка:
K>Жалко, что лямбда не может передаваться как указатель на функцию, надеялся тут есть какой-то способ схитрить.

почему не может передаваться?

typedef void (*api_callback_t)(int);
extern void api_function(api_callback_t fun);
....
auto lambda = [](int) {
}
api_function(lambda);


или речь о чем-то другом?
Веру-ю-у! В авиацию, в научную революци-ю-у, в механизацию сельского хозяйства, в космос и невесомость! Веру-ю-у! Ибо это объективно-о! (Шукшин)
Re[4]: Лямбда как параметр в функцию
От: koenjihyakkei Россия  
Дата: 30.07.15 11:36
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>А какая разница какой размер функции ?


Захламливать хедер не хочется.
Re[4]: Лямбда как параметр в функцию
От: koenjihyakkei Россия  
Дата: 30.07.15 11:37
Оценка: +1
Здравствуйте, dad, Вы писали:

dad>или речь о чем-то другом?


Лямбда с захватом контекста.
Re[7]: Лямбда как параметр в функцию
От: _NN_ www.nemerleweb.com
Дата: 30.07.15 11:51
Оценка:
Здравствуйте, enji, Вы писали:

E>Не понял идеи, можно пример? Как можно получить обычный указатель, имея замыкание?


E>
E>typedef void(*P)();

E>void g(P);

E>void f(int a) {
E>  P p = [a]{ std::cout<<a; }; // ???
E>  g(p);
E>}

E>


Идея проста, генерировать код на лету как это делает например библиотека ATL или тот же .NET .
Мы имеем объект, генерируем переходник в виде ассемблерных инструкций и его подставляем как указатель на функцию.
Конечно это не переносимо и платформо-зависимо, но если будет в стандарте то каждый компилятор будет реализовывать как надо для платформы.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: Лямбда как параметр в функцию
От: enji  
Дата: 31.07.15 08:42
Оценка:
Здравствуйте, _NN_, Вы писали:

E>>
E>>typedef void(*P)();

E>>void g(P);

E>>void f(int a) {
E>>  P p = [a]{ std::cout<<a; }; // ???
E>>  g(p);
E>>}

E>>


_NN>Идея проста, генерировать код на лету как это делает например библиотека ATL или тот же .NET .


Я все еще не понимаю, как в данном случае сгенерировать такой код в компайл-тайме? Надо ж как-то запихать туда значение переменной "a", как это сделать?
Или имеется в виду генерация во время выполнения?
Re[9]: Лямбда как параметр в функцию
От: watchmaker  
Дата: 31.07.15 11:08
Оценка:
Здравствуйте, enji, Вы писали:

E>Или имеется в виду генерация во время выполнения?


Конечно, именно это. Никто о compile-time и не говорил.
Re[10]: Лямбда как параметр в функцию
От: enji  
Дата: 31.07.15 11:49
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Конечно, именно это. Никто о compile-time и не говорил.


А по каким позывам удалять этот сгенерированный код? Тогда все равно нужно что-то типа shared_ptr, голый указатель не пойдет

И кстати возникает вопрос, зачем оно в данном случае надо (почему не std::function)?
Re[11]: Лямбда как параметр в функцию
От: watchmaker  
Дата: 31.07.15 12:41
Оценка: 4 (1)
Здравствуйте, enji, Вы писали:


E>И кстати возникает вопрос, зачем оно в данном случае надо (почему не std::function)?

В данном случае — не надо. Это просто ещё один способ со своими недостатками. Автор темы спросил в начале какие есть альтернативы std::function — ему ответили — вот и всё.

Если же тебя интересуют именно случаи, когда такой подход оправдан, то они практически все описываются ситуацией «есть callback api без возможности передачи контекста». Тогда в случае, когда, callback функции всё же нужен контекст (например, то же лямбде нужно получить доступ к захваченным данным), динамическая генерация прокси-функции обеспечит место для его хранения и передачи.
Но такие ситуации, к счастью, встречаются не так уж часто. Ведь иногда можно просто api исправить (если есть исходники и есть возможность их менять) и использовать std::function (только для C++) или пару указателей на код и данные (в общем случае, не только для не C++).

E>А по каким позывам удалять этот сгенерированный код? Тогда все равно нужно что-то типа shared_ptr, голый указатель не пойдет

А это ортогональная проблема. Например, после new int возникнет тот же вопрос «когда удалять?» эти данные. Удаляй когда они больше не нужды. Компилятор за тебя этот вопрос не решит. Ну, а способы отслеживать «нужность» уже известны. Можно и самому отслеживать, голыми указателями обходясь, можно и в shared_ptr или unique_ptr завернуть. Некоторые подходы будут в среднем лучше других, но в общем случае каждый имеет право на жизнь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.