Лямбда - получить свой this
От: T4r4sB Россия  
Дата: 01.02.22 18:50
Оценка:
Как известно, лямбда это сахарок над объектов, у которого перегружен оператор ().
Но как получить ссылку на этот объект внутри этого оператора? Бывает полезно, в том числе для рекурсивного вызова.
Пока что все решения рекурсивных лямбд какой-то отстой. И приходится по старинке в стиле ++03 городить локальную структуру с методом.
Re: Лямбда - получить свой this
От: σ  
Дата: 01.02.22 19:23
Оценка: 19 (2) +1
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#recursive-lambdas
Отредактировано 01.02.2022 19:25 σ . Предыдущая версия .
Re: Лямбда - получить свой this
От: Alexander G Украина  
Дата: 01.02.22 19:24
Оценка: 4 (1)
Здравствуйте, T4r4sB, Вы писали:

TB>Как известно, лямбда это сахарок над объектов, у которого перегружен оператор ().

TB>Но как получить ссылку на этот объект внутри этого оператора? Бывает полезно, в том числе для рекурсивного вызова.
TB>Пока что все решения рекурсивных лямбд какой-то отстой.

В C++23 приняли http://wg21.link/p0847 Deducing this

В частности, там есть Recursive Lambdas.

Всё, что до этого — да, отстой.
Русский военный корабль идёт ко дну!
Re[2]: Лямбда - получить свой this
От: T4r4sB Россия  
Дата: 01.02.22 19:25
Оценка:
Здравствуйте, σ, Вы писали:

σ>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r6.html#recursive-lambdas


Но это же лишь пропозалы...
Re[3]: Лямбда - получить свой this
От: σ  
Дата: 01.02.22 19:27
Оценка: +1
σ>>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#recursive-lambdas

TB>Но это же лишь пропозалы...


https://github.com/cplusplus/draft/pull/5002
Re: Лямбда - получить свой this
От: sergii.p  
Дата: 01.02.22 19:31
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Но как получить ссылку на этот объект внутри этого оператора?


первое, что пришло на ум: передать её саму себе в качестве захвата и при этом стереть тип

#include <iostream>
#include <vector>
#include <functional>

int main()
{
    std::function<int(int*, int*)> sum;
    sum = [&sum](int* begin, int* end) {
        return (begin != end) ? sum(begin + 1, end) + *begin : 0;
    };
    std::vector<int> v {1, 2, 3};
    std::cout << sum(&*v.begin(), &*v.end());
    return 0;
}


не нравится сам std::function, не нравится, что не напишешь в параметрах auto. Но работает...
Re[2]: Лямбда - получить свой this
От: T4r4sB Россия  
Дата: 01.02.22 19:33
Оценка: +2
Здравствуйте, sergii.p, Вы писали:

SP>первое, что пришло на ум: передать её саму себе в качестве захвата и при этом стереть тип


Это оверхед
Re: Лямбда - получить свой this
От: Videoman Россия https://hts.tv/
Дата: 01.02.22 21:50
Оценка: 1 (1) +1
Здравствуйте, T4r4sB, Вы писали:

TB>Как известно, лямбда это сахарок над объектов, у которого перегружен оператор ().

TB>Но как получить ссылку на этот объект внутри этого оператора? Бывает полезно, в том числе для рекурсивного вызова.

Может быть что-то такое:
auto sum = [](auto& func, auto begin, auto end)->int {
    return (begin != end) ? func(func, begin + 1, end) + *begin : 0;
};

std::vector<int> v{ 1, 2, 3 };
std::cout << sum(sum, v.begin(), v.end());

Правда уродский синтаксис вызова, но там уже всё уродское, на мой взгляд
http://www.gravatar.com/avatar/60560936caa07b944d4c3cecf1c06cc5?s=80&d=identicon
Re: Лямбда - получить свой this
От: AlexGin Беларусь  
Дата: 02.02.22 02:08
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>Пока что все решения рекурсивных лямбд какой-то отстой.


+100500
IMHO лямбды — не лучшее решение таких задач.
Что-то подсказывает мне, что изначально авторы лямбд ориентировались на задачи не рекурсивного характера.
Вот, например, поиск в коллекции, тот же std::find_if — весьма удобное (и удобочитаемое) применение лямбд:

https://gist.github.com/hrafnkelle/2639849

Любое другое решение с рекурсивными вызовами — будет смотреться красивее и читабельнее.
Re[2]: Лямбда - получить свой this
От: T4r4sB Россия  
Дата: 02.02.22 06:07
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Правда уродский синтаксис вызова, но там уже всё уродское, на мой взгляд


И по сути указатель на лямбду передаётся два раза — потому что вызов лямбды это вызов метода класса, а метод класса и так передаёт первым параметром указатель на экземпляр класса. То есть это как object.foo(object, 1, 2, 3) в вызове не-статичного метода. Ну не уродство?
Re[3]: Лямбда - получить свой this
От: Videoman Россия https://hts.tv/
Дата: 02.02.22 07:23
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>И по сути указатель на лямбду передаётся два раза — потому что вызов лямбды это вызов метода класса, а метод класса и так передаёт первым параметром указатель на экземпляр класса. То есть это как object.foo(object, 1, 2, 3) в вызове не-статичного метода. Ну не уродство?


В принципе, вот
Автор: sergii.p
Дата: 01.02.22
нормальное решение в части стирания типа, которое отлично оптимизируется в релизе. Опиши полностью задачу которую ты решаешь, тогда можно будет что-то конкретно посоветовать. Рекомендуемый подход для рекурсии вызова такой:
using it = typename std::vector<int>::iterator;

std::function<int(it, it)> sum = [&sum](it begin, it end) {
    return (begin != end) ? sum(begin + 1, end) + *begin : 0;
};
http://www.gravatar.com/avatar/60560936caa07b944d4c3cecf1c06cc5?s=80&d=identicon
Re[2]: Лямбда - получить свой this
От: Jack128  
Дата: 02.02.22 09:28
Оценка:
Здравствуйте, AlexGin, Вы писали:

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


TB>>Пока что все решения рекурсивных лямбд какой-то отстой.


AG>+100500

AG>IMHO лямбды — не лучшее решение таких задач.
AG>Что-то подсказывает мне, что изначально авторы лямбд ориентировались на задачи не рекурсивного характера.
AG>Вот, например, поиск в коллекции, тот же std::find_if — весьма удобное (и удобочитаемое) применение лямбд:

В языках без локальных функций, народ очень быстро начинает использовать лямбды в качестве замены. Так было в шарпе, видимо тоже самое в плюсах происходит..
Re[2]: Лямбда - получить свой this
От: Alexey Nikitin Россия  
Дата: 02.02.22 17:57
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Правда уродский синтаксис вызова, но там уже всё уродское, на мой взгляд


Синтаксис вызова можно подправить, прикопав уродскость поглубже)

auto sum = [](auto begin, auto end){
    auto sum_impl = [](auto begin, auto end, auto func) -> int  {
            return (begin != end) ? func(begin + 1, end, func) + *begin : 0;
        };
        return sum_impl(begin, end, sum_impl);
    };
Re[3]: Лямбда - получить свой this
От: Sm0ke Россия http://ksi.ru.net/
Дата: 02.02.22 20:01
Оценка:
Здравствуйте, Alexey Nikitin, Вы писали:

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


V>>Правда уродский синтаксис вызова, но там уже всё уродское, на мой взгляд


AN>Синтаксис вызова можно подправить, прикопав уродскость поглубже)


AN>
AN>auto sum = [](auto begin, auto end){
AN>    auto sum_impl = [](auto begin, auto end, auto func) -> int  {
AN>            return (begin != end) ? func(begin + 1, end, func) + *begin : 0;
AN>        };
AN>        return sum_impl(begin, end, sum_impl);
AN>    };
AN>


А если надо захватывать переменные? Перезахватывать их глубже тоже? Нормальная тема.
Re[3]: Лямбда - получить свой this
От: T4r4sB Россия  
Дата: 02.02.22 20:08
Оценка:
Здравствуйте, Alexey Nikitin, Вы писали:


AN> return sum_impl(begin, end, sum_impl);


Тут sum_impl передаётся в параметры два раза. Первый раз в качестве this неявно, второй раз явно.
Ну не уродство, а?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.