Здравствуйте, ArtDenis, Вы писали: AD>В русте макросы настолько круты, что могут своровать твой закрытый ключ при открытии проекта с макросом: https://github.com/lucky/bad_actor_poc
Раз уж шутка зашла...
В русте макросы настолько круты, что позволяют в коде делать инлайн-вставки кода на си и плюсах с возможностью отладки
Здравствуйте, ArtDenis, Вы писали:
AD>В русте макросы настолько круты, что позволяют в коде делать инлайн-вставки кода на си и плюсах с возможностью отладки
AD>https://docs.rs/cpp/latest/cpp/
Ну наконец-то теперь на расте можно писать на плюсах
Здравствуйте, netch80, Вы писали:
N>Можно подробнее про расстреливание ног?
К сожалению потерял ссылку на презентацию, в которой чуть-ли не через слайд было "вы видите тут UB? а оно есть" (( Но вообще при аккуратном и простом использовании плюсовые корутины вполне себе нормальные. Главное — держать ухо (asan) востро
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Помню, как в начале 90-х все пищали: "ах, шаблоны — это так круто и удобно, попрощаемся же навсегда с macro hell". Теперь мы уже много лет имеем template hell, но настолько привыкли считать, что шаблоны — это круто, что как-то даже стыдно думать об альтернативах. А ведь на обработку сотен-тысяч навороченных макросов требовались ничтожные, по нынешним временам, ресурсы, но сейчас обработка сравнимого количества шаблонов требует многократно бОльших ресурсов, а отлаживать их нередко бывает сложнее, чем макросы.
Ты сравниваешь несравнимое. Шаблоны вместе с системой типов образуют своеобразный _ДЕКЛАРАТИВНЫЙ_ язык программирования,
где компилятор самостоятельно ищет и применяет подходящее решение по заданным программистом правилам (описаниям
шаблонов, типов, функций...)
А макросы -- это просто подстановка текста.
Никакого hell ни там, ни там нет. Нужно просто понимать и уметь пользоваться.
Отлаживать шаблоны проще, т.к. современные компиляторы (кроме, может быть доисторических версий студии) умеют разворачивать сообщения об ошибках с раскрытием параметров подставляемых в шаблон на каждом шаге.
ЕМ>Современные компиляторы используют предкомпиляцию шаблонов, но она, по сути, не столько ускоряет компиляцию вообще, сколько снижает тормоза, создаваемые множеством многоуровневых шаблонных конструкций. И все равно оптимизатору приходится как-то систематизировать функции, чтобы объединить те, что отличаются только типами, но при этом не оформлены ни в шаблоны, ни в перегрузки.
Шаблоны "предкомпилируются" только на уровне синтаксического разбора. Предкомпилировать их принципиально невозможно, т.к. конкретные типы и параметры шаблона обретают конкретный смысл только в момент использования шаблона. Этим часто пользуются, чтобы отложить компиляцию класса, например, к моменту первого использования шаблона. Что позволяет использовать в определении класса ещё не определённые типы, например.
ЕМ>Считается, что функциональный стиль использования шаблонов — это благо, но многие ли способны быстро разобраться в иерархии и взаимодействии шаблонов в какой-нибудь Boost? В конце концов, какая часть математиков интуитивно воспринимает факториал, как отображение множества целых чисел само на себя, или, на худой конец, как рекурсию, а не как последовательное (итеративное) произведение?
Прочитал, ничего не понял. Если понимать систему шаблонов, как я сказал выше, как декларативный ЯВУ, то достаточно быстро всё становится на места. Если интерпретировать по-привычке сверху-вниз, то наврное тяжело.
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Все преимущества остались бы. Так как шаблоны -- это ни разу не подстановка текста. Шаблоны исторически выросли из макропроцессора, да. Но сейчас уже совсем другие времена...
В обычном макропроцессоре вполне можно использовать циклические конструкции (единственное что -- глубина рекурсии принципиально ограничена, хотя может быть достаточно глубокой, с шаблонами, кстати, та же история), хотя и нетривиальным способом. Да, пожалуй это трюк который следовало изобрести (первые публикации где-то 2011 год, если не позже, а существует макропроцессор с 80-х). Идея в том, что во-первых нужно многократное раскрытие текста макроса (пропорционально глубине рекурсии), что осуществляется при передаче текста аргументом в другой макрос. Во-вторых, рекурсия искусственно прерывается только когда препроцессор в процессе раскрытия макроса наталкивается на макрос с тем же именем, что раскрываемый сейчас. Соответственно можно устроить пинг-понг macro1 -> macro2 -> macro1 -> macro2... где многократное разворачивание последовательности выполняется внешним псевдо-рекурсивным макросом вызванным многократно, много раз (лимит не нужен, можно вызвать с глубиной 999, например, и если на 300-м разе всё раскрылось, на последующих итерациях текст просто останется неизменным). Пример: https://github.com/swansontec/map-macro
Что значит "параметры вызова разобрать"?
Разница шаблонов с макропроцессором в том, что макропроцессор не понимает смысла в тексте который он подставляет, а шаблоны связаны с грамматикой и системой типов языка. И это не подстановка. Шаблон генерирует новую сущность в терминах самого языка.
S>Помнится в колледже я писал библиотеку работы с матрицей, узнал даже про перегрузку операторов, ведь мне нужно было умножение. S>Про шаблоны не знал, да вроде и не было ещё тогда их. S>Тогда я думал какой взять тип элемента float или double. И сделал typedef. S>Потом появилась идея заменить typedef макросом для типа и префикса перед инклюдом библиотеки, чтобы можно было одновременно пользоваться разными матрицами и не писать сто раз одно и тоже. Есть #define, есть #undef — так это можно было сделать. Не очень красиво, зато работает.
S>Когда я узнал про шаблоны и стал их осваивать сам (на уроке про них тогда не рассказывали), то понял — вот оно. Не надо инклюдить несколько раз один файл, а просто подставить нужный тип элемента и всё.
S>И не городить огород инклюдов с передифайнами. 1 строчка на дифайн префикса, 1 строчка на дифайн типа, 1 строчка на каждый инклюд. А если надо больше параметров-типов? И не забыть про андифайны после инклюда!
Так а что мешает сделать макрос, которому передаётся тип, а дальше он всё делает: генерирует фунцкии и структуры данных с нужным типом и всё такое прочее... И не городить огород. Это -- типовое решение, из него и выросли шаблоны.
S>Вы предлагаете вернуться к макросам? Как вы решите такую задачу?
Немного отошёл бы от типового решения. Вместо того, весь код писать в макросах всё немного вывернул бы наизнанку.
Но честно говоря, само знание, что так можно появляется только после знакомства с C++.
Идея такая:
1) существуют какие-то конкретные специфичные типы, весь код для работы с ними дробится на
элементарные операции (из буквально пары строчек кода) и описывается в отдельных функциях
(можно сразу декларировать inline static для удобства);
2) для каждого типа существует что-то вроде "таблицы виртуальных функций", только она не таскается
в самом типе и не вычисляется в рантайме -- это чисто статическая, константная, определяемая в момент
компиляции вещь: в таблице (структура с именованными членами -- указателями на функции) функции из пункта 1;
3) функции из п.1 и сам п.2 могут генерироваться макросом (т.к. их нужно параметризовать конкретным
типом, не известным в момент описания функции), параметром макроса является тип, например;
4) существует аналог std::any<T>, который представляет обобщённый тип (аллоцирует память в своём теле
или динамически, предоставляет ссылку на структуру указателей на функции оперирующих над конкретным
типом хранимым в данном обобщённом типе;
5) существует набор функций выполняемых над обобщённым типом -- фактически прокси, вызывающие операции
из структуры специфичной для данного типа из п.1, с помощью структуры из п.2, ссылка на которую
хранится в п.4.
В итоге хотя макросы и есть, но они описывают простые примитивные функции, а не портянку на три страницы,
в которой легко сделать ошибку и невозможно потом отладить. Основной код не в макросе, а в обычном виде записан.
Поскольку структуры носящие указатели на реальные функци оперирующие над конкретными типами -- константы,
то компилятор может в целом их подставлять прямо непосредственно, т.е. код может генерироваться почти
что оптимальный. Примерно как это происходит с шаблонами в C++.
Немного муторно, шаблоны удобней, да.
S>Макросы помогут скажем сделать умножение двух матриц с разными типами элемента? Если да, то покажите как. S>Да хоть на любой другой задаче...
Здравствуйте, удусекшл, Вы писали:
ЕМ>>>Я предлагаю сравнить функциональнось и удобство современных шаблонов с адекватно реализованными макросами. Если Вы никогда не видели макросов, отличных от сишных, то Вам нет смысла и сравнивать.
S>>Конкретные примеры можно? Я же не буду искать все реализации макросов вообще во всех языках ...
У>Я так понимаю, что он хочет что-то типа доступа к AST, чтобы можно было писать простые функции с циклами, набивающие AST дополнительными штуками, и чтобы эти функции писались на том же C++ и исполнялись во время компиляции. Что-то такое есть в C# вроде.
Или в Rust. На мой взгляд такие "макросы" только хуже шаблонов в C++. На них может быть легко сделать какие-то отдельные трюки, которые не сделать в C++, но в целом любая более-менее сложная задача решаемая в шаблонах на C++ с такими императивными макросами заканчивается тем, что нужно для решения задачи вначале на языке этого макропроцессора написать какой-то интерпретатор своего языка, в терминах которого уже и решать задачу. Короче говоря -- ещё сложней. Шаблоны в C++ более-менее хорошо предназначены для решения прикладных задач, а интроспекция в C# и макросы в Rust -- позволяют с одной стороны что угодно, а с другой что-то сложное сделать примерно так же просто, как программировать на ассемблере. Т.е. можно, но оно того не стоит.
Re[10]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, ArtDenis, Вы писали:
AD>>Можно пример как это может выглядеть?
ЕМ>Ну вот шаблоны type traits реализованы так, что для определенных типов они явно специализированы с нужными значениями констант, а для остальных выбираются варианты по умолчанию. То есть, это устроено задом наперед, при этом установка и извлечение значений констант работает, по сути, на побочных явлениях. Если бы в языке был способ "интеллектуального" раскрытия хоть макросов, хоть шаблонов, то можно было бы проверять заданный параметром тип обычными условными конструкциями вроде #ifdef.
То получилось бы полное говно. Потому, что специализацию шаблона для нового типа T легко взять и дописать. В сторонке где-то. А твой #ifdef -- получается нужно заранее знать наперёд все возможные типы. И дописать нельзя.
Такое уже сделали в Rust. Нет, сама идея трейтов у них осталась, т.е. с твоей точки зрения всё задом наперёд тоже. Но у них ничего кроме трейтов нет, у них невозможны вычисления зависимые от типа. Т.е. в C++ можно на основе каких-то наперёд не известных свойств неизвесного наперёд типа что-то расчитать и получить новые типы, или константы, или функции и т.п. Зависимые от свойств типа. Вычисляемых в момент компиляции. То в Rust получается нужно заранее для каждого типа наперёд написать Traits<T> с нужными свойствами. Когда тип библиотечный -- фигня вопрос. Когда тип свой -- уже морока. А когда тип сам по себе чужой и тоже наперёд заранее неизвестный -- пиши пропало. Кто-то другой должен это всё расписать, а он ни сном, ни духом, что оно такое нужно. Для каких-то библиотечных трейтов так можно сделать, но в целом когда соединяются множество независимых компонентов -- возникнут проблемы.
ЕМ>А если бы в языке изначально были условные конструкции, работающие на уровне компилятора (вроде __if_exists в MSVC), то из этого естественным образом вытекало бы и наличие встроенных предикатов для типов, переменных, функций, шаблонов и прочего. Вот тогда было бы одновременно и удобно, и красиво, и в реализации недорого.
Ну так эти конструкции и есть в шаблонах. Просто с твоей точки зрения оно "вывернуто наизнанку". Но если вывернуть как хочешь ты получится гораздо хуже по другим причинам.
Re[14]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, ArtDenis, Вы писали:
AD>>Не получается. Хочу примеры
ЕМ>Ну вот, например, примитивно, на псевдокоде, максимально приближенном к C/C++:
ЕМ>
О чём я и говорил -- тебе нужно все типы знать наперёд. И char не обязательно signed. А "signed char" вот стопроцентно signed, а у тебя в списке отсутствует. Как и "short", и "long long".
ЕМ>Хотя и это тоже извращение. Для таких вещей любой вменяемый компилятор обязан иметь встроенные предикаты.
std::is_signed...
Re[10]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, ArtDenis, Вы писали:
AD>>В русте макросы настолько круты, что могут своровать твой закрытый ключ при открытии проекта с макросом: https://github.com/lucky/bad_actor_poc
AD>Раз уж шутка зашла...
AD>В русте макросы настолько круты, что позволяют в коде делать инлайн-вставки кода на си и плюсах с возможностью отладки
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, Sm0ke, Вы писали:
S>>Конкретные примеры можно?
ЕМ>Ну вот один из простейших — у Turbo Assembler (а ему навеяно макроассемблером Macro-11).
ЕМ>Смысл в том, чтобы в макрос можно было включить и условия, и повторы, и преобразования параметров.
Повторы в макросах возможны. Условия тоже в какой-то мере. По крайней мере макрос может или детектировать число аргументов, или что остаток аргументов не пуст, или детектировать некий условный маркер конца. В принципе всё что кроме подсчёта числа аргументов (известным паттерном, все наверное знают) делается через попытку подстановки (не)пустого значения между одним именем макроса и круглыми скобками. Известная же наверное вещь, интуитивно же понятно.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, Sm0ke, Вы писали:
S>>Конкретные примеры можно?
ЕМ>Ну вот один из простейших — у Turbo Assembler (а ему навеяно макроассемблером Macro-11).
ЕМ>Смысл в том, чтобы в макрос можно было включить и условия, и повторы, и преобразования параметров.
А что такое вот это, "преобразование параметров"? Откуда и куда их преобразовать нужно?
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
AG>Трудно сказать, что было бы, если бы было то, чего нет.
AG>В отладочной сборке по шаблонным функциям можно пошагать отладчиком. Ну или даже в не-отладочной, если оно не заинлайнилось. AG>С нынешними макро так не работает. AG>Непонятно, работало бы ли это с гипотетическим макро процессором.
С макросами gdb с -g3 тоже в теории может. Но проблема же в том, что макросы, и шаблоны, могут не только простую подстановку, например, типа делать, но и более сложные вещи. В итоге они управляют генерацией кода, и код может получиться совсем не такой как ожидает программист, и типы данных, да вообще всё. Там уже не до пошаговой отладки будет -- и это в любом более-менее сложном случае.
Здравствуйте, netch80, Вы писали:
N>Я вот тут наблюдаю один вполне себе серьёзный важный проект. Уровень — C с классами. Люди — умеют свою тематику, серьёзный телеком. Геттер вида string getX() { return x_; } где "string x_"; — норма. А рядом вдруг uint8& getY() { return y_; } Const и noexcept, понятно, у обоих не стоит. Впрочем, поскольку это всё в конфигурировании (а не в hot path), всем пофиг. N>Реально, "широкие народные массы" сейчас в районе C++11, не сильно выше.
Зато на работу пойдёшь трудоустраиваться, сразу спрашивают: "Cколько у вас лет опыта на C++23?"..
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Я не очень понимаю, что делает в профльном форуме эта околонаучная фантастика? Как можно всерьез обсуждать то, чего нет?