EP>>>template<typename ConcreteCoroutine, typename R, typename... Args> struct coroutine_traits; EP>>>[/ccode]Где соответвенно тип ConcreteCoroutine будет разным для: EP>>>
EP>>>generator<int> iota(int n);
EP>>>
и для EP>>>
EP>>>generator<int> even(int n);
EP>>>
Несмотря на то что у них одинаковые типы параметров и результата, потому что их локальные переменные И код могут быть разным. х>>Хорошо, но где хранить разность (их локальные переменные)? После вызова этой функции у нас есть только generator<int>
EP>Нет, вот тут не верно. EP>После вызова, у нас объект типа который определяется через corountine_traits<ConcreteCoroutine, generator<int>, int>. И этот тип может зависеть от ConcreteCoroutine, а может не зависеть — по желанию автора специализации.
Так... А откуда вызывающий код знает тип ConcreteCoroutine? Конкретный тип лежит уже в реализации (.cxx файле), вызывающий код не знает какой там размер. Можно конечно через extenral const прокинуть размер объекта, но тогда ломается возможность косвенного вызова функции по указателю:
Здравствуйте, х, Вы писали:
EP>>Нет, вот тут не верно. EP>>После вызова, у нас объект типа который определяется через corountine_traits<ConcreteCoroutine, generator<int>, int>. И этот тип может зависеть от ConcreteCoroutine, а может не зависеть — по желанию автора специализации.
х>Так... А откуда вызывающий код знает тип ConcreteCoroutine? Конкретный тип лежит уже в реализации (.cxx файле), вызывающий код не знает какой там размер.
Точно также как и с лямбдами — их код должен быть доступен, потому что по факту они определяют новый анонимный тип, то же самое и с корутинами. При этом если есть необходимость, то всегда можно стереть тип через std::function.
Также для корутин может быть автоматические послабление в зависимости от того что решит специализация corountine_traits — если тип стирается, то тело не нужно, если не стирается — то нужно. Но даже эта фича не является необходимой, так как если есть конкретный тип — легко перейти к стёртому.
Ты кстати не привёл ручную реализацию three — неужели не получается без аллокаций?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Точно также как и с лямбдами — их код должен быть доступен, потому что по факту они определяют новый анонимный тип, то же самое и с корутинами.
Ну так бы сразу и сказал, что предлагаешь инлайнить корутины. Я пас: это убьёт саму идею спрятать кишки работы с сетью и другими устройствами в корутины.
Здравствуйте, х, Вы писали:
EP>>Точно также как и с лямбдами — их код должен быть доступен, потому что по факту они определяют новый анонимный тип, то же самое и с корутинами. х>Ну так бы сразу и сказал, что предлагаешь инлайнить корутины.
Ну я сразу сказал что не хочу безалтернативное стирание типа.
х>Я пас: это убьёт саму идею спрятать кишки работы с сетью и другими устройствами в корутины.
1. Это, извиняюсь, откровенная чушь. Ибо возможность "прятать кишки" никуда не исчезла. Точно также как и сейчас можно сделать:
std::function<int()> make();
И "спрятать кишки", в которых может быть хоть обычный тип, хоть лямбда, не смотря на то что у лямбды вполне конкретный тип и размер.
2. Корутины они не только для работы с сетью и устройствами, там действительно в большинстве случаев лишняя аллокация не так страшна. На них ещё можно делать генераторы, которые очень широко применимы И для которых эта лишняя аллокация плюс убийство инлайнинга очень сильно сужает область практического применения
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ну я сразу сказал что не хочу безалтернативное стирание типа.
Ты сказал что предлагаешь избавится от new, мне сдало интересно как. Много сообщений спустя я узнал как. Больше нет вопросов.
EP>1. Это, извиняюсь, откровенная чушь. Ибо возможность "прятать кишки" никуда не исчезла. Точно также как и сейчас можно сделать: EP>
EP>std::function<int()> make();
EP>
И "спрятать кишки", в которых может быть хоть обычный тип, хоть лямбда, не смотря на то что у лямбды вполне конкретный тип и размер.
std::function<int()> приводит к new. То что корутины это просто попытка избавиться от callback hell известно.
EP>2. Корутины они не только для работы с сетью и устройствами, там действительно в большинстве случаев лишняя аллокация не так страшна. На них ещё можно делать генераторы, которые очень широко применимы И для которых эта лишняя аллокация плюс убийство инлайнинга очень сильно сужает область практического применения
Генераторы как раз можно и заинлайнить через шаблоны и лябды, что убирает new. Так что обойтись без new как раз осталась.
Здравствуйте, х, Вы писали:
EP>>1. Это, извиняюсь, откровенная чушь. Ибо возможность "прятать кишки" никуда не исчезла. Точно также как и сейчас можно сделать: EP>>
EP>>std::function<int()> make();
EP>>
И "спрятать кишки", в которых может быть хоть обычный тип, хоть лямбда, не смотря на то что у лямбды вполне конкретный тип и размер. х>std::function<int()> приводит к new.
Ну так:
1. Нужно type-erasure — получите аллокацию в общем случае и отсутсвие инлайнинга.
2. Не нужно — используйте конкретный тип и покажите его определение.
В том что я предлагаю доступно и 1. и 2., на выбор. То есть можно либо "спрятать кишки", либо "показать", в зависимости от хотелок, точно также как и с лямбдами.
В том что имеем в стандарте — всегда получаем стирание типа, плюс сказки про heap allocation elision optimization
EP>>2. Корутины они не только для работы с сетью и устройствами, там действительно в большинстве случаев лишняя аллокация не так страшна. На них ещё можно делать генераторы, которые очень широко применимы И для которых эта лишняя аллокация плюс убийство инлайнинга очень сильно сужает область практического применения х>Генераторы как раз можно и заинлайнить через шаблоны и лябды, что убирает new. Так что обойтись без new как раз осталась.
Каким образом сделать это в общем случае? Там результирующий тип чисто по-построению зависит только от типов параметров и типа резултата, и не зависит от конкретной реализации.
Это точно также как если в std::for_each передавать указатель на функцию — инстанцияция std::for_each будет одна на каждый тип указателей на функцию. В некоторых частных случаях этого можно соптимизировать сделав больше инлайнига, но в общем случае это чисто технически невозможно, например если указатель на функцию сохранён в поле класса. В то же время если передавать лямбду — то каждая лямбда будет пораждать разную инстанцияцию std::for_each, на порядки облегчая работу оптимизатора.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ну так: EP>1. Нужно type-erasure — получите аллокацию в общем случае и отсутсвие инлайнинга. EP>2. Не нужно — используйте конкретный тип и покажите его определение.
Так если хочешь инлайны, то бери шаблоны и лябды — ноль аллокаций и всё быстро. Зачем для этого новая сущность? Корутины ввели для облегчения callback hell — и именно эту проблему они решают хорошо.
Здравствуйте, х, Вы писали:
EP>>Ну так: EP>>1. Нужно type-erasure — получите аллокацию в общем случае и отсутсвие инлайнинга. EP>>2. Не нужно — используйте конкретный тип и покажите его определение. х>Так если хочешь инлайны, то бери шаблоны и лябды — ноль аллокаций и всё быстро. Зачем для этого новая сущность? Корутины ввели для облегчения callback hell — и именно эту проблему они решают хорошо.
Корутины позволяют автоматически нарезать функцию на продолжения, значительно сокращая и распутывая зашумлённый код. Два самых крупных применения этому — генераторы и await, есть и другие.
Соответсвенно в том же C#, или даже Python — они также присутсвуют и в виде yield, и в виде await, так как обе фичи являются реально полезными. Даже в функциональных языках это доступно в виде более общей концепции монад.
И даже в новом стандарте C++ — есть и co_yield и co_await. То есть корутины помогают решать задачи в самых разных областях. Правильно реализованные stackless корутины, с поддержкой перемещения, копирования и рефлексированния контекста, покрыли бы ещё большой класс задач решаемых монадами.
Ты судя по-всему, осведомлён только об одном каком-то специфичном use-case'е, близком к твоей прикладной области, и проецируешь частные требования на все корутины, что никак недопустимо говоря о языке с таким широким применением как C++
Твоё предложение использовать шаблоны и лямбды вместо корутин — абсурдно, ибо означает "нарезай код на продолжения вручную" и проблему распутывания кода никак не решает, а по сути отрицает
В целом даже непонятно с чем ты споришь, ибо возвможность доступа к конкретному типы корутины была бы крайне полезна для одних use-case'ов, и не мешала бы остальным, так как при необходимости тип элементарно стирается. win-win. Хочешь слепо защищать авторов этого конкретного proposal — ну удачи
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Ты судя по-всему, осведомлён только об одном каком-то специфичном use-case'е, близком к твоей прикладной области, и проецируешь частные требования на все корутины, что никак недопустимо говоря о языке с таким широким применением как C++ EP>Твоё предложение использовать шаблоны и лямбды вместо корутин — абсурдно, ибо означает "нарезай код на продолжения вручную" и проблему распутывания кода никак не решает, а по сути отрицает
EP>В целом даже непонятно с чем ты споришь, ибо возвможность доступа к конкретному типы корутины была бы крайне полезна для одних use-case'ов, и не мешала бы остальным, так как при необходимости тип элементарно стирается. win-win. Хочешь слепо защищать авторов этого конкретного proposal — ну удачи
Сколько написал то... В общем если тебе надо скорость и ты готов реализацию инлайнить, то шаблонов и лабд достаточно для всего, что ты написал. Со временем научишься ими пользоваться и вопрос снимешь сам. Ну или просто поищи как это реализовано у других, достаточно элегантно.
Делать предположения обо мне довольно глупо. Я вижу твою тягу к нравоучениям, но так же вижу, что в плюсах ты плаваешь, так как ты допускаешь высказывания в тексте, которые ни один профи ни делает. Я ж не тыкаю тебя носом в это (твою не опытность). Зачем ты пробуешь принизить собеседника?
Ладно — я больше отвечать не буду. Если будет что-то по существу пиши. Если снова чешется чему-то меня научить, лучше найти другого слушателя.
Здравствуйте, okman, Вы писали:
O>Изучаю C++20. В целом все понятно, но одна вещь вызывает наибольшие затруднения — корутины.
Решил глянуть нововведения и, внезапно, основная масса описаний внутренностей корутин, включая те что в этом теме фигурируют не отличаются вразумительностью или нужным уровнем детализации.
Здравствуйте, Евгений Музыченко, Вы писали:
O>>корутины.
ЕМ>Отчего эта корявая калька так расплодилась в народе? Есть же (еще с середины прошлого века) отличный термин — сопрограммы. Прям тест на знание истории программирования.
Термины это всегда боль Мое представление, что указанные coroutine
1. никакого отношения с многозадачности не имеют, и достаточно легки для понимания (функция со стейтом или стейт машина над кусками кода). Для примера вот объяснение здесь
2. на них можно натянуть многозадачность также как и на все другое, и вот здесь начинается основные вопросы...
ЗЫ. Я честно говоря сам пока не разобрался со всей этой фигней очень не хочется лезть в стандарт, надеюсь, что кто-то уже разжевал, и может внятно объяснить как это работает