В вашем комментарии речь шла о чейн функциях, в моем примере они есть. Не понимаю в чем вы видите различие вызов через точку или вызов через | ? Семантически это одно и то же. И да лямбды в плюсах уродливые, тут ничего с этим не сделаешь.
И в плюсах оператор точку не то чтобы нежелательно, её нельзя перегрузить для чужого класса.
Использование функций для этого не совсем кошерно, можно использовать constexpr переменные, дабы получить более вкусный синтаксис. Условно (value->as_int) навариваем сюда концептов и получаем забавный способ что-то сделать
Я думал о глобальных константах вместо функций. Но есть функции с параметрами, их constexpr переменными не сделаешь.
Да можно. Но опять таки это только про работу над списками. А хочется применить не только для списков. Надо попробовать старые ranges затащить в мой C++17 проект, вроде сторонних зависимостей нет
Это значит, что какая-то библиотечная функция уже вернула вам объект, например строку std::string, которую она создала. И тут у вас есть только возможность обернуть возвращённую строку в вашу строку с дополнительным методом.
Да в C# самая корявая реализация, но это было первое что я увидел в 2012. А так да UFCS то что надо. В Kotlin мне, например, нравится явность определения функции как метода:
// обычная функция
fun <T> first(list: List<T>) = list[0]
// метод - расширение
fun <T> List<T>.first() = this[0]
Кстати Wikipedia говорит, что
This has again, in 2023, been proposed by Herb Sutter[13] claiming new information and insights as well as an experimental implementation in the cppfront compiler.
Возможно мы в каком-то стандарте и увидим такой синтаксический сахар, может и доживём.
Ну потратил он один раз 5 минут разобрался и дальше проблем не возникает. Мне этот поход зашел в одном реальном проекте, ranges я не могу использовать потому я ограничен C++17, а цепочечные преобразования очень хочется, так как надоело писать постоянно императивные for. Я наклепал по быстрому различные функции над коллекциями, mapToVector, toSet, toVector, joinToString, reduce и теперь пишу однострочники в стиле ranges:
Второе где пригодилось это при сериализации моделек данных в Json, мой последний пример. Я сперва пробовал сыграть на перегрузке функции toJson для разных типов, но в итоге столкнулся в шаблонном коде с тем, что компилятор довольно мудрёно ищет подходящие перегрузки и словил кучу проблем с неймспейсами и позицией в коде что первее чего объявлено. Переписал toJson на такой "метод расширения" и всё теперь работает просто и понятно, достаточно перегрузить оператор для нужного типа. Также можно писать конвертеры, например toDto, toModel:
Да, всё верно. Вроде такая простая и полезная фича, а затянуть не могут. Мне не понятно. Зато выкатывают какие-то мудреные странные фичи для каких-то корнер кейсов.
Я поработал с этим в других языках, начиная с C# в 12 году, мне очень зашло, теперь жить без них не могу.
Я проэмулировал, оно немного коряво, но на практике пользоваться удобно, написал один раз помучился, но потом кайфуешь. Ну а про диалекты, чтож, в плюсах это на каждом шагу. Кто-то макросы изобретает, кто-то шаблонную магию, которую очень сложно понять. Таков язык. Если в проекте это используется системно, то все привыкают и тоже используют. Да и std::ranges в принципе это то же самое, только понавороченнее.
Правильно ответили. Наследование это сложнее (из-за конструкторов) и не возможно, когда это библиотечный код. Да и обобщённый код сложнее написать, чтобы был один шаблонный метод и работал с множество разных типов. С шаблонными функциями это всё возможно, но пользоваться неудобно (пример - алгоритмы в C++).
Про шероховатости. Не совсем их вижу. Мы же пишем функцию, там явно указываем тип ссылки на объект, *, &. const ... Компилятор только должен её увидеть и попробовать подставить. В приоритете конечно методы объекта, но потом можно пробовать и функции с подходящей сигнатурой. То что творится в шаблонах вас не смущает, SFINAE например, когда компилятор перебирает кучу всего подряд пытаясь найти подходящее?
Не совсем понял к чему тут объяснение что такое лямбда? Причем, у вас пример не правильный, не хватает
[]
в начале.Какой синтаксический сахар? Синтаксис лямбды в C++ сложно назвать сахаром 😅
Чукча писатель, не читатель. Полагаю откуда-то копипастилось не глядя, и html эскепинг просочился
В вашем комментарии речь шла о чейн функциях, в моем примере они есть. Не понимаю в чем вы видите различие вызов через точку или вызов через
|
? Семантически это одно и то же. И да лямбды в плюсах уродливые, тут ничего с этим не сделаешь.И в плюсах оператор точку не то чтобы нежелательно, её нельзя перегрузить для чужого класса.
Так я же привёл пример реализации функции
transform
, это как раз и есть прямой аналогlet
в Kotlin. Остальные функции можно сделать по аналогии.И я надеюсь, что компилятор это способен оптимизировать до простых вызовов.
О, я даже и не знал что такой оператор есть ) Да, синтаксис вызова неудобный, не подойдёт
Сперва подумал что это что-то на матерном ) Почитаю про это )
Но я просто хотел показать как проэмулировать методы расширения. Ranges прикручивать не каждому надо, и заниматься высшей магией с ниеблоидами.
Я думал о глобальных константах вместо функций. Но есть функции с параметрами, их constexpr переменными не сделаешь.
Ну я это не в библиотеке использую, а в своём проекте. В библиотеке я, наверное бы, не стал навязывать такие интерфейсы.
Да можно. Но опять таки это только про работу над списками. А хочется применить не только для списков. Надо попробовать старые ranges затащить в мой C++17 проект, вроде сторонних зависимостей нет
Ну вот патчить компилятор это вообще последнее дело
О даааа =)
Жалко что нельзя свои операторы определять, вот тогда бы вообще раздолье было бы )
Кстати в Котлин есть инфиксные функции, наверное и в других каких-то языках есть тоже. Можно делать так:
Да в плюсах с лямбдами туго, мне тоже не хватает упрощённого синтаксиса.
В С# (кажется это он) ещё не очень лаконично. Вот то же на Котлине, вот где красота:
Это значит, что какая-то библиотечная функция уже вернула вам объект, например строку std::string, которую она создала. И тут у вас есть только возможность обернуть возвращённую строку в вашу строку с дополнительным методом.
Да в C# самая корявая реализация, но это было первое что я увидел в 2012. А так да UFCS то что надо. В Kotlin мне, например, нравится явность определения функции как метода:
Кстати Wikipedia говорит, что
Возможно мы в каком-то стандарте и увидим такой синтаксический сахар, может и доживём.
Да, я перегрузил
|
по аналогии с библиотекой ranges, хотя можно было перегрузить и оператор>>
, было бы нагляднее.К сожалению оператор
->
и.
нельзя перегрузить вне класса. Да и это бы вносило путаницу с указателями.Да, но в стандартной библиотеке это применимо только к потокам. Я просто обобщил. Ну и флоу тут "обратный" потокам.
Ну потратил он один раз 5 минут разобрался и дальше проблем не возникает. Мне этот поход зашел в одном реальном проекте, ranges я не могу использовать потому я ограничен C++17, а цепочечные преобразования очень хочется, так как надоело писать постоянно императивные for. Я наклепал по быстрому различные функции над коллекциями, mapToVector, toSet, toVector, joinToString, reduce и теперь пишу однострочники в стиле ranges:
Второе где пригодилось это при сериализации моделек данных в Json, мой последний пример. Я сперва пробовал сыграть на перегрузке функции toJson для разных типов, но в итоге столкнулся в шаблонном коде с тем, что компилятор довольно мудрёно ищет подходящие перегрузки и словил кучу проблем с неймспейсами и позицией в коде что первее чего объявлено. Переписал toJson на такой "метод расширения" и всё теперь работает просто и понятно, достаточно перегрузить оператор для нужного типа. Также можно писать конвертеры, например toDto, toModel:
Да, всё верно. Вроде такая простая и полезная фича, а затянуть не могут. Мне не понятно. Зато выкатывают какие-то мудреные странные фичи для каких-то корнер кейсов.
Я поработал с этим в других языках, начиная с C# в 12 году, мне очень зашло, теперь жить без них не могу.
Я проэмулировал, оно немного коряво, но на практике пользоваться удобно, написал один раз помучился, но потом кайфуешь. Ну а про диалекты, чтож, в плюсах это на каждом шагу. Кто-то макросы изобретает, кто-то шаблонную магию, которую очень сложно понять. Таков язык. Если в проекте это используется системно, то все привыкают и тоже используют. Да и std::ranges в принципе это то же самое, только понавороченнее.
Правильно ответили. Наследование это сложнее (из-за конструкторов) и не возможно, когда это библиотечный код. Да и обобщённый код сложнее написать, чтобы был один шаблонный метод и работал с множество разных типов. С шаблонными функциями это всё возможно, но пользоваться неудобно (пример - алгоритмы в C++).
Про шероховатости. Не совсем их вижу. Мы же пишем функцию, там явно указываем тип ссылки на объект, *, &. const ... Компилятор только должен её увидеть и попробовать подставить. В приоритете конечно методы объекта, но потом можно пробовать и функции с подходящей сигнатурой. То что творится в шаблонах вас не смущает, SFINAE например, когда компилятор перебирает кучу всего подряд пытаясь найти подходящее?
Интересная тулза, поставлю себе. Но она вроде как не решает мои задачи, она совсем не про то.