Спасибо, правда минус в том, что функция довольно большая и тащить ее в хедер из-за шаблона не хочется.
Жалко, что лямбда не может передаваться как указатель на функцию, надеялся тут есть какой-то способ схитрить.
Здравствуйте, koenjihyakkei, Вы писали:
K>Спасибо, правда минус в том, что функция довольно большая и тащить ее в хедер из-за шаблона не хочется. K>Жалко, что лямбда не может передаваться как указатель на функцию
Лямбда без захвата — может. Не твой случай?
K> надеялся тут есть какой-то способ схитрить.
Способы-то есть. Например, можно использовать динамическую генерацию прокси-функций. Тогда в библиотечную функцию передаётся уникальный указатель на прокси, а сама прокси-функция уже может передавать управление на лямбду.
Впрочем эта (и аналогичные хитрости) оправданы только в самых крайних случаях — когда интерфейс вообще нет возможности поменять (например, из-за отсутствия исходников). В нормальном же режиме лучше всё-таки использовать std::function. Ну или хотя бы пару указателей (на код функции и на контекст, как это, собственно, и делается повсеместно в С и различных API).
Здравствуйте, watchmaker, Вы писали:
W>Лямбда без захвата — может. Не твой случай?
Не мой, в захвате вся соль.
W>Способы-то есть. Например, можно использовать динамическую генерацию прокси-функций. Тогда в библиотечную функцию передаётся уникальный указатель на прокси, а сама прокси-функция уже может передавать управление на лямбду. W>Впрочем эта (и аналогичные хитрости) оправданы только в самых крайних случаях — когда интерфейс вообще нет возможности поменять (например, из-за отсутствия исходников). В нормальном же режиме лучше всё-таки использовать std::function. Ну или хотя бы пару указателей (на код функции и на контекст, как это, собственно, и делается повсеместно в С и различных API).
Ну это уж слишком замороченные хитрости
Пока сделал через std::function. Просто код в какой-то мере платформозависимый и не факт, что в продакшене std вообще будет. Но пока покатит, дальше видно будет)
Здравствуйте, koenjihyakkei, Вы писали: K>Пока сделал через std::function. Просто код в какой-то мере платформозависимый и не факт, что в продакшене std вообще будет. Но пока покатит, дальше видно будет)
Ну, свой костыль никогда не поздно будет дописать.
K>Спасибо, правда минус в том, что функция довольно большая и тащить ее в хедер из-за шаблона не хочется.
А какая разница какой размер функции ?
Единственная проблема заголовочного файла это включение дополнительных зависимостей.
Если их нет, то и проблемы нет в принципе.
K>Жалко, что лямбда не может передаваться как указатель на функцию, надеялся тут есть какой-то способ схитрить.
Можно если нет захвата контекста.
А вообще давно пора иметь такой механизм, будем надеется , что в будущем такое добавят.
Здравствуйте, _NN_, Вы писали:
_NN>А какая разница какой размер функции ? _NN>Единственная проблема заголовочного файла это включение дополнительных зависимостей. _NN>Если их нет, то и проблемы нет в принципе.
Проблема еще и в раздувании объема программы — будет создано по одной копии функции на каждую точку вызова (подозреваю все лямбды имеют разный тип)
_NN>А вообще давно пора иметь такой механизм, будем надеется , что в будущем такое добавят.
Что ты имеешь в виду? std::function и есть такой механизм...
Здравствуйте, enji, Вы писали:
E>Здравствуйте, _NN_, Вы писали:
_NN>>А какая разница какой размер функции ? _NN>>Единственная проблема заголовочного файла это включение дополнительных зависимостей. _NN>>Если их нет, то и проблемы нет в принципе. E>Проблема еще и в раздувании объема программы — будет создано по одной копии функции на каждую точку вызова (подозреваю все лямбды имеют разный тип)
Да ладно. Неужели вы считаете компилятор настолько тупым ?
Ну и даже размер будет больше это не так страшно как рисуется.
Сомневаюсь, что у вас получится накинуть мегабайт на каждое воплощение шаблона.
Ну и std::function тоже не так страшен как его рисуют.
Там как минимум есть оптимизация с использованием стека для простых случаев.
_NN>>А вообще давно пора иметь такой механизм, будем надеется , что в будущем такое добавят.
E>Что ты имеешь в виду? std::function и есть такой механизм...
Не, именно генерацию кода и получение обычного указателя на функцию в стиле C.
Где-то пробегала ссылка на предложение включить это в стандарт.
Здравствуйте, 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));
}
Вот как-то так. Корявенько и многословно, зато эффективно.
Здравствуйте, _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);
}
Здравствуйте, 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 .
Мы имеем объект, генерируем переходник в виде ассемблерных инструкций и его подставляем как указатель на функцию.
Конечно это не переносимо и платформо-зависимо, но если будет в стандарте то каждый компилятор будет реализовывать как надо для платформы.
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", как это сделать?
Или имеется в виду генерация во время выполнения?
E>И кстати возникает вопрос, зачем оно в данном случае надо (почему не std::function)?
В данном случае — не надо. Это просто ещё один способ со своими недостатками. Автор темы спросил в начале какие есть альтернативы std::function — ему ответили — вот и всё.
Если же тебя интересуют именно случаи, когда такой подход оправдан, то они практически все описываются ситуацией «есть callback api без возможности передачи контекста». Тогда в случае, когда, callback функции всё же нужен контекст (например, то же лямбде нужно получить доступ к захваченным данным), динамическая генерация прокси-функции обеспечит место для его хранения и передачи.
Но такие ситуации, к счастью, встречаются не так уж часто. Ведь иногда можно просто api исправить (если есть исходники и есть возможность их менять) и использовать std::function (только для C++) или пару указателей на код и данные (в общем случае, не только для не C++).
E>А по каким позывам удалять этот сгенерированный код? Тогда все равно нужно что-то типа shared_ptr, голый указатель не пойдет
А это ортогональная проблема. Например, после new int возникнет тот же вопрос «когда удалять?» эти данные. Удаляй когда они больше не нужды. Компилятор за тебя этот вопрос не решит. Ну, а способы отслеживать «нужность» уже известны. Можно и самому отслеживать, голыми указателями обходясь, можно и в shared_ptr или unique_ptr завернуть. Некоторые подходы будут в среднем лучше других, но в общем случае каждый имеет право на жизнь.