Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 12.02.18 18:26
Оценка:
Здравствуйте!

Может, неправильно выразился, но суть такая: есть необходимость использовать callback'и, функторы для этого хорошо подходят. Но хочется иметь возможность передавать туда и лямбды с непустыми []. Специфика такова, что нет ни std::function, ни тем более boost'а.

Какие есть варианты? Желательно попроще
Маньяк Робокряк колесит по городу
Re: Связать лямбду
От: reversecode google
Дата: 12.02.18 18:36
Оценка:
а пример того чего хочется но не компилится — можно ? а то не понятно
Re[2]: Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 12.02.18 18:53
Оценка:
Здравствуйте, reversecode, Вы писали:


R>а пример того чего хочется но не компилится — можно ? а то не понятно


Хм. Сейчас даже не и не скажу. Это моя первая лямбда

Колега возится, у него жирный шаблон инстанциируется, он изобретает какую-то либу колбеков, чтобы уменьшить размер результирующего кода — шутка ли сказать — каждое инстанциирование по 1Кб кода добавляет

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

Вот, как-то так
Сорри, если сумбурно, только начал грызть 11 стандарт
Думал, сами догадаетесь, в чем проблема, а то я пока не осознал


ЗЫ Хотя, я сделал нечто похожее на то, что у коллеги, только без колбеков внутри, мой класс получился нешаблонным, сверху навернул шаблон на пять строчек, добавил туда колбек шаблонным параметром, который любые лямбды кушает так же как и функторы, и теперь думаю, что коллега что-то не совсем то хочет сделать
Маньяк Робокряк колесит по городу
Re: Связать лямбду
От: Alexander G Украина  
Дата: 12.02.18 19:13
Оценка: +2
Здравствуйте, Marty, Вы писали:

M>Специфика такова, что нет ни std::function, ни тем более boost'а.


Чем именно вызван отказ от std::function ?

Что ещё нельзя? Вариадики, type traits?

Дело в том, что навернуть что-то своё можно, но оно не будет лучше std::function, если покрывать самый общий случай.
Русский военный корабль идёт ко дну!
Re: Связать лямбду
От: reversecode google
Дата: 12.02.18 19:18
Оценка: 39 (5)
https://github.com/jamboree/CxxFunctionBenchmark
вот пример всевозможных вариаций, народ с рсдн вроде игрался
может там чего для себя найдете
Re[2]: Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 12.02.18 19:19
Оценка:
Здравствуйте, Alexander G, Вы писали:

M>>Специфика такова, что нет ни std::function, ни тем более boost'а.


AG>Чем именно вызван отказ от std::function ?


Его нет в компиляторе


AG>Что ещё нельзя? Вариадики, type traits?


Вариадики вроде есть, как работают — не знаю, вроде худо-бедно пашут. type traits —


AG>Дело в том, что навернуть что-то своё можно, но оно не будет лучше std::function, если покрывать самый общий случай.


Ну вот ребята там что-то подобное и пилят уже месяц почти; я, как новый человек в конторе вообще, и незнакомый с C++11 в частности, пока особо в это не лезу. Но как-то за пол-дня прикрутил к коду с аналогичным функционалом лямбду, вот и думаю, что они там пилят, и главное, надо ли
Маньяк Робокряк колесит по городу
Re[2]: Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 12.02.18 19:20
Оценка:
Здравствуйте, reversecode, Вы писали:


R>https://github.com/jamboree/CxxFunctionBenchmark

R>вот пример всевозможных вариаций, народ с рсдн вроде игрался
R>может там чего для себя найдете

Спс, завтра на свежую голову гляну
Маньяк Робокряк колесит по городу
Re[3]: Связать лямбду
От: reversecode google
Дата: 12.02.18 19:23
Оценка:
M>Ну вот ребята там что-то подобное и пилят уже месяц почти; я, как новый человек в конторе вообще, и незнакомый с C++11 в частности, пока особо в это не лезу. Но как-то за пол-дня прикрутил к коду с аналогичным функционалом лямбду, вот и думаю, что они там пилят, и главное, надо ли

срочно опубликовать этот щедевр для мема сюда http://govnokod.ru/cpp
Re[4]: Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 12.02.18 19:23
Оценка:
Здравствуйте, reversecode, Вы писали:

M>>Ну вот ребята там что-то подобное и пилят уже месяц почти; я, как новый человек в конторе вообще, и незнакомый с C++11 в частности, пока особо в это не лезу. Но как-то за пол-дня прикрутил к коду с аналогичным функционалом лямбду, вот и думаю, что они там пилят, и главное, надо ли


R>срочно опубликовать этот щедевр для мема сюда http://govnokod.ru/cpp



Нельзя. Секретность
Маньяк Робокряк колесит по городу
Re[3]: Связать лямбду
От: Alexander G Украина  
Дата: 12.02.18 19:34
Оценка:
Здравствуйте, Marty, Вы писали:

M>Ну вот ребята там что-то подобное и пилят уже месяц почти; я, как новый человек в конторе вообще, и незнакомый с C++11 в частности, пока особо в это не лезу. Но как-то за пол-дня прикрутил к коду с аналогичным функционалом лямбду, вот и думаю, что они там пилят, и главное, надо ли


Ну, надо ли. Случаи разные бывают.
Если не нужен type erasure, можно просто передавать как выводимый шаблонный параметр.

Если не надо поддерживать любые сигнатуры, только для одной, то задача тоже сильно упрощается.

Если лямбду не нужно хранить, а только спускать вниз по стеку, то через указатель на лямбду можно упростить.

Хорошая реализация, такая как в boost::function, помимо обеспечения type erasure, с поддержкой всех сигнатур, и хранением лябмды в себе, делает ещё следующее:
1. Избегает полиморфизма на C++ классах в пользу полиморфизма на указателях на функции. То есть чтобы на все возможные сигнатуры не было пачки RTTI и vtable.
2. Делает small value optimization, то есть, если лямбда небольшая хранит её не на куче, а по значению.
Русский военный корабль идёт ко дну!
Re[4]: Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 12.02.18 19:43
Оценка:
Здравствуйте, Alexander G, Вы писали:

M>>Ну вот ребята там что-то подобное и пилят уже месяц почти; я, как новый человек в конторе вообще, и незнакомый с C++11 в частности, пока особо в это не лезу. Но как-то за пол-дня прикрутил к коду с аналогичным функционалом лямбду, вот и думаю, что они там пилят, и главное, надо ли


AG>Ну, надо ли. Случаи разные бывают.

AG>Если не нужен type erasure, можно просто передавать как выводимый шаблонный параметр.
AG>Если не надо поддерживать любые сигнатуры, только для одной, то задача тоже сильно упрощается.

Ну вот они как раз и уперлись в поддержку любых сигнатур. Хз, зачем, правда.


AG>Если лямбду не нужно хранить, а только спускать вниз по стеку, то через указатель на лямбду можно упростить.


Тут хз, но, скорее всего, таки нужно хранить


AG>Хорошая реализация, такая как в boost::function, помимо обеспечения type erasure, с поддержкой всех сигнатур, и хранением лябмды в себе, делает ещё следующее:

AG>1. Избегает полиморфизма на C++ классах в пользу полиморфизма на указателях на функции. То есть чтобы на все возможные сигнатуры не было пачки RTTI и vtable.
AG>2. Делает small value optimization, то есть, если лямбда небольшая хранит её не на куче, а по значению.

Кучи нет. Кстати
Маньяк Робокряк колесит по городу
Re[5]: Связать лямбду
От: Alexander G Украина  
Дата: 12.02.18 20:49
Оценка: 11 (3) +1
Здравствуйте, Marty, Вы писали:

M>Кучи нет. Кстати


Ого. Ну как-то так можно, раз new запрещён, остаётся фиксированный буфер в себе:

template<std::size_t BufferSize, class R, class... Args>
class LambdaStorage
{
public:
    template<class F>
    LambdaStorage(F f)
    {
        new (data) F(f);
        call = CallImpl<F>;
        copy = CopyImpl<F>;
        del  = DelImpl<F>;        
    }

    LambdaStorage()
    {
        call = nullptr;
        copy = nullptr;
        del  = nullptr;
    }

    LambdaStorage(const LambdaStorage& other)
    {
        call = other.call;
        copy = other.copy;
        del  = other.del ;
        copy(data, other.data);
    }

    ~LambdaStorage()
    {
        if ( del != nullptr )
            del(data);
    }

    LambdaStorage& operator=(const LambdaStorage& other) = delete;

    R operator()(Args... args)
    {
        return call(data, args...);
    }

private:
    template<class F>
    static R CallImpl(const char* data, Args... args)
    {
        const F* f = reinterpret_cast<const F*>(data);
        return (*f)(args...);
    }

    template<class F>
    static void CopyImpl(char* dest, const char* src)
    {
        const F* f = reinterpret_cast<const F*>(src);
        new (dest) F(*f);
    }

    template<class F>
    static void DelImpl(char* data)
    {
        const F* f = reinterpret_cast<const F*>(data);
        f->~F();
    }

    R    (*call) (const char* data, Args...);
    void (*copy) (char* dest, const char* src);
    void (*del)  (char* data);

    char data[BufferSize];
};

typedef LambdaStorage<16, int, const char*, int> MyCallable;

MyCallable MakeCallable()
{
    int i = 22;
    return [i](const char* s, int j)
    {
        std::cout << s << '\n';
        return (i+j);
    };
}

void UseCallable(MyCallable c)
{
    int r = c("Hello world!", 20);
    std::cout << "Result " << r << '\n';
}

int main()
{
    MyCallable c = MakeCallable();
    UseCallable(c);
    return 0;
}


(решение подлежит оптимизации, если что, это наглядная версия)
Русский военный корабль идёт ко дну!
Отредактировано 12.02.2018 21:02 Alexander G . Предыдущая версия . Еще …
Отредактировано 12.02.2018 20:50 Alexander G . Предыдущая версия .
Re[5]: Связать лямбду
От: PM  
Дата: 14.02.18 00:45
Оценка: 9 (2) +1
Здравствуйте, Marty, Вы писали:

AG>>Хорошая реализация, такая как в boost::function, помимо обеспечения type erasure, с поддержкой всех сигнатур, и хранением лябмды в себе, делает ещё следующее:

AG>>1. Избегает полиморфизма на C++ классах в пользу полиморфизма на указателях на функции. То есть чтобы на все возможные сигнатуры не было пачки RTTI и vtable.
AG>>2. Делает small value optimization, то есть, если лямбда небольшая хранит её не на куче, а по значению.

M>Кучи нет. Кстати


Я такое делал, кто-то с форума помогал советами и отзывами, тему неудобно с планшета искать сейчас. Результат лежит на https://github.com/pmed/fixed_size_function

Размер фиксированного буфера под лямбду задается параметром шаблона, ещё от 2 до 4 указателей уходит на функции вызова, деструктора, копирования и перемещения лямбды.

Однако если нет кучи, то проще все-таки использовать лямбды без захвата состояния, чтобы свести все к указателю на функцию. Вменяемые интерфейсы обычно так и проектируют, закладывают какой-нибудь void* аргументом callback функции:
using callback = void (*)(void* user_data, float x);

void explode(int y, callback cb, void* user_data);

struct world { ... } my;

explode(1000, [](void* data, float x){ auto my = static_cast<world*>(data); ... }, &my);
Re[3]: Связать лямбду
От: anonymouse2 Иностранный Агент
Дата: 15.02.18 17:56
Оценка:
Здравствуйте, Marty, Вы писали:

AG>>Чем именно вызван отказ от std::function ?

M>Его нет в компиляторе

Как такое возможно что лямбды есть в компиляторе а std::function нет???
Да и вообще это же заголовочный файл, его скорее всего можно затащить оттуда где он есть (из другого компилятора, из буста и т.д.)
Нет такого преступления, на которое не пошло бы суверенное родоплеменное быдло ради продления своего бессмысленного рода и распространения своего бессмысленного генома.
Re[4]: Связать лямбду
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 15.02.18 18:00
Оценка:
Здравствуйте, anonymouse2, Вы писали:

AG>>>Чем именно вызван отказ от std::function ?

M>>Его нет в компиляторе

A>Как такое возможно что лямбды есть в компиляторе а std::function нет???

A>Да и вообще это же заголовочный файл, его скорее всего можно затащить оттуда где он есть (из другого компилятора, из буста и т.д.)


Вроде пробовали, не взлетело. Это embedded, детка
А Keil, конкретно, с тех пор как я увидел его в первый раз в 96ом году, ни капельки не изменился Для меня было шоком, что он поддерживает 11 плюсовый стандарт, пусть и с урезанной STL
Маньяк Робокряк колесит по городу
Re: Связать лямбду
От: Mr.Delphist  
Дата: 19.02.18 17:08
Оценка:
Здравствуйте, Marty, Вы писали:

M> Здравствуйте!


M>Может, неправильно выразился, но суть такая: есть необходимость использовать callback'и, функторы для этого хорошо подходят. Но хочется иметь возможность передавать туда и лямбды с непустыми []. Специфика такова, что нет ни std::function, ни тем более boost'а.


M>Какие есть варианты? Желательно попроще


Я правильно понимаю, что хочется что-то вроде std::bind?
http://en.cppreference.com/w/cpp/utility/functional/bind12
Re[3]: Связать лямбду
От: T4r4sB Россия  
Дата: 19.02.18 22:07
Оценка:
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, Alexander G, Вы писали:


M>>>Специфика такова, что нет ни std::function, ни тем более boost'а.


AG>>Чем именно вызван отказ от std::function ?


M>Его нет в компиляторе


Сделай велосипед. Элементарно пишется, если не надо 100500 фич с биндами и прочим.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.