Помню, как в начале 90-х все пищали: "ах, шаблоны — это так круто и удобно, попрощаемся же навсегда с macro hell". Теперь мы уже много лет имеем template hell, но настолько привыкли считать, что шаблоны — это круто, что как-то даже стыдно думать об альтернативах. А ведь на обработку сотен-тысяч навороченных макросов требовались ничтожные, по нынешним временам, ресурсы, но сейчас обработка сравнимого количества шаблонов требует многократно бОльших ресурсов, а отлаживать их нередко бывает сложнее, чем макросы.
При этом, изрядная доля macro hell происходила лишь от того, что обработка исходника была искусственно разделена на препроцессирование и компиляцию. В начале 70-х это еще можно было как-то оправдать нехваткой ресурсов, хотя убогие возможности сишного препроцессора вряд ли могли заметно утяжелить компилятор. Имей компилятор возможность хотя бы просто выдать в сообщении об ошибке как исходную конструкцию, так и результат ее обработки макропроцессором, это свело бы на нет бОльшую часть проблем.
Современные компиляторы используют предкомпиляцию шаблонов, но она, по сути, не столько ускоряет компиляцию вообще, сколько снижает тормоза, создаваемые множеством многоуровневых шаблонных конструкций. И все равно оптимизатору приходится как-то систематизировать функции, чтобы объединить те, что отличаются только типами, но при этом не оформлены ни в шаблоны, ни в перегрузки.
Считается, что функциональный стиль использования шаблонов — это благо, но многие ли способны быстро разобраться в иерархии и взаимодействии шаблонов в какой-нибудь Boost? В конце концов, какая часть математиков интуитивно воспринимает факториал, как отображение множества целых чисел само на себя, или, на худой конец, как рекурсию, а не как последовательное (итеративное) произведение?
Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Макросы в конечном итоге это просто подмена текста. Что там и на что подменяется компилятор проверять не обязан. А шаблоны это генератор типов, когда заранее известно, что работаем с конструкциями типов. Или те же константы тоже проходят оптимизацию, когда объявляются как константы, а не как макросы замены.
Я не углублялся в теорию компиляторов, но суть отказа от макросов при компиляции в оптимизации, которую проводит компилятор переводя конструкции языка в машинный код. Твоя же мысль звучит как давайте создадим более продвинутый генератор, который позволит учитывать ещё больше. Но где гарантия, что к примеру у тебя получится создать что-то лучше, а не те же шаблоны C++ только с перламутровыми пуговицами.
ЕМ>Теперь мы уже много лет имеем template hell, но настолько привыкли считать, что шаблоны — это круто, что как-то даже стыдно думать об альтернативах.
Альтернатива это берёшь те же шаблоны C++ и создаёшь на их основе свои библиотеки алгоритмов. Лично я считаю, что это проблема в расхождении видения понятий. Один программист видит вот так и пишет код вот так. А другой видит по другому и у него другой алгоритм и другие названия. Хотя решают они одну и ту же задачу.
Та же STL, ей можно принебречь, как и Boost. И создать свою библиотеку с нуля, которая будет выделять память как нужно конкретному программисту и многое другое вплоть до системных вызовов. Да, язык это позволяет, а то что многим удобно использовать стандартные контейнеры, алгоритмы и итераторы, то это совершенно другой вопрос.
Или вот, если тебе всё ещё нравится стиль Си, а макросы о которых мы говорим это именно они, и хотя они поддерживаются в C++ ими можно уже не пользоваться, так попробуй сделать на них что-нибудь адекватное. И первая проблема та же самая, это сложное создание своей собственной библиотеки алгоритмов, а использование чужой такой же hell как и везде, хоть в макросах, хоть в шаблонах.
Короче люди подсели на фреймворки и прочие чужие библиотеки алгоритмов, а всё потому, что написать что-то своё долго, сложно и дорого. А проблема фреймворков везде, и что они сложные через пень колоду, и что постоянно меняются. А что, выбор есть, фреймворк или свой велосипед. Лично я это с языками программирования не связываю.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Трудно сказать, что было бы, если бы было то, чего нет.
В отладочной сборке по шаблонным функциям можно пошагать отладчиком. Ну или даже в не-отладочной, если оно не заинлайнилось.
С нынешними макро так не работает.
Непонятно, работало бы ли это с гипотетическим макро процессором.
Здравствуйте, velkin, Вы писали:
V>Макросы в конечном итоге это просто подмена текста. Что там и на что подменяется компилятор проверять не обязан.
Это примитивные, убогие сишные макросы, которые в C++ перетащили для совместимости, заранее объявив абсолютным злом, и постеснявшись хоть как-то улучшить.
V>А шаблоны это генератор типов, когда заранее известно, что работаем с конструкциями типов.
Идея макросов изначально состояла в генерации произвольного кода, в том числе и с параметрами типов. В Си макросы часто применялись именно для простой типизации, именно в этом их эффективно заменили шаблоны. Но большинство проблем макросов, повторю, возникало именно из-за разобщенности препроцессора и компилятора, когда управлять порождением можно было лишь набором абстрактных констант, и нельзя было использовать для этого свойства определенных к тому времени программных сущностей (переменных, функций, типов, классов и т.п.). Когда это пытались делать параллельно, конструкции быстро становились громоздкими, часто возникали ошибки синхронизации параллельных макросов друг с другом.
V>Я не углублялся в теорию компиляторов, но суть отказа от макросов при компиляции в оптимизации, которую проводит компилятор переводя конструкции языка в машинный код. Твоя же мысль звучит как давайте создадим более продвинутый генератор, который позволит учитывать ещё больше. Но где гарантия, что к примеру у тебя получится создать что-то лучше, а не те же шаблоны C++ только с перламутровыми пуговицами.
Мне хороший макропроцессор всегда виделся главным образом процедурным, а не функциональным. В таком стиле макрос напоминает функцию, которая выполняет операции над своими параметрами, результатом которых становится код, подлежащий обработке компилятором. То, что на шаблонах принято делать рекурсией (смысл и работа которой далеко не всегда очевидны) и не так давно реализованной распаковкой параметров, в макропроцессорах всегда делалось обычными циклическими конструкциями. То, что на шаблонах делается многоуровневыми (и опять же не всегда очевидными) вызовами предикатов, в нормальном макропроцессоре выглядело бы обычными условными конструкциями.
V>Альтернатива это берёшь те же шаблоны C++ и создаёшь на их основе свои библиотеки алгоритмов.
Ну, это не намного удобнее, чем делать на макросах в их существущем виде. Пока все просто и ортогонально, оно выглядит изящно и логично, но с ростом сложности библиотеки сложность записи растет очень быстро, и довольно скоро превращается в уродливую мешанину, половину которой составляют костыли.
V>Один программист видит вот так и пишет код вот так. А другой видит по другому и у него другой алгоритм и другие названия.
Это все верно, но у шаблонов главная проблема — в недостатке выразительных средств. Этакое прокрустово ложе, к которому периодически приделывают полочки, чтобы можно было ставить стакан или класть телефон, но лежать от этого удобнее не становится.
V>если тебе всё ещё нравится стиль Си, а макросы о которых мы говорим это именно они
Мне не нравится ни "стиль Си", ни "стиль C++" в их крайних вариантах. И то, и другое одинаково убого и уродливо, разве что последний позволяет больше спрятать под капотом до того момента, как капот сорвет давлением изнутри. А вот имей язык возможность определять макросы более широко, и порождать из них программный код более гибко — глядишь, и macro hell бы удалось изжить, и template hell вместо него не нажить.
V>хотя они поддерживаются в C++ ими можно уже не пользоваться, так попробуй сделать на них что-нибудь адекватное.
Так о том и речь, что на этом примитиве невозможно сделать ничего адекватного — как, например, и на простейшем бэйсике. Но из невозможности сделать что-то серьезное на простейшем бэйсике отнюдь не следует, что этого не сделать на любом процедурном ЯП, и спасение нужно искать исключительно в функциональных. Функциональный стиль хорош там, где сам алгоритм описан в функциональных терминах. Тащить его всюду лишь потому, что "круто и модно", не стоит.
V>люди подсели на фреймворки и прочие чужие библиотеки алгоритмов, а всё потому, что написать что-то своё долго, сложно и дорого.
Раньше "сложно и дорого" означало "нужны десять человек, год времени и миллион долларов", а в нынешнем мире программ-однодневок это нередко выливается в "нужен еще один человек, две недели и пять тысяч, но с фреймворком можем обойтись одним, сляпаем за неделю и две тысячи, все равно через полгода выкидывать".
Здравствуйте, Alexander G, Вы писали:
AG>В отладочной сборке по шаблонным функциям можно пошагать отладчиком.
А по сложным выражениям никогда нельзя было пошагать отладчиком иначе, как в режиме дизассемблера. Я бы не отказался от возможности пошагать по отдельным операциям в выражении.
AG>Непонятно, работало бы ли это с гипотетическим макро процессором.
Элементарно. Макропроцессору, встроенному в компилятор, нетрудно оформить порожденный код в отдельный набор строк для отладчика, который кладется в БД с отладочной информацией. Ниоткуда ведь не следует, что отладчик может показывать только то, что лежит в исходных файлах.
Собственно, это можно было бы делать и для существующего препроцессора, но во времена, когда макросы были актуальны, символьных отладчиков, работавших с исходниками, почти не было, а потом макросы объявили вселенским злом, и уже принципиально не стали облегчать работу с ними.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Здравствуйте, Евгений Музыченко, Вы писали: ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Ым... Получились бы шаблоны. С каким-то вариациями, конечно, но именно нынешние шаблоны и получились бы.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
В свое время одна моя студентка написала вот такой примерно код
#define N 5;
// ...for(int i = 0; i < N *2; i++) {
//
}
Я потратил не помню уж сколько времени, пытаясь понять, что все это значит, и откуда тут indirection, если никаких указателей и близко нет. Пока не догадался посмотреть результат препроцессинга. Посмотреть сам макрос мне в голову не пришло, я и не подумал, что N — это макрос.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Пока не догадался посмотреть результат препроцессинга.
Если бы это был не убогий внешний пре-, а нормальный встроенный макропроцессор, компилятор мог бы выдать вместе с сообщением об ошибке и окрестность конструкции, которая ему не нравится.
Впрочем, содержательность диагностики большинства компиляторов C/C++ — отдельное убожество. Страшно представить, сколько человеко-лет было потрачено впустую из-за этого упертого минимализма.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Темплеты нужно по-любому в достаточно явном виде.
Другой вопрос, что именно их раскрытие — процесс, который сейчас пишется в извращённом виде неявно на языке темплетов, который представляет собой один из худших функциональных языков, которые могут быть, с выражением всех пожеланий в косвенном виде. А мог бы вместо этого иметь явные конструкции для контроля типов, выбора вариантов и прочих необходимых действий...
ЕМ>Если бы это был не убогий внешний пре-, а нормальный встроенный макропроцессор, компилятор мог бы выдать вместе с сообщением об ошибке и окрестность конструкции, которая ему не нравится.
Для этого он должен бы стать компилятором. Только при компиляции выясняется, корректна ли та или иная конструкция или нет. Что, собственно, с шаблонами и имеет место быть.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ> из-за этого упертого минимализма.
Зато Govno Compiler Collection тебе в случае опечатки в параметре шаблонной функции тебе выдаст развёрнутое эссе на тему каждой перегрузки этого шаблона, почему же он не смог тут её применить, и ты будешь не менее минуты листать это эссе, докапываясь до истины. При этом если у тебя где-то случайно делается копирование некопируемого объекта, то в его 1000-страничном эссе не будет ни единого упоминания места, где ты случайно забыл сделать мув или поставить ссылку. А если ты забыл заимплементить метод в реальном наследнике абстрактного класса, то у тебя только линкер скажет, что не найдена ТВМ, и ты наверное даже по этому сообщению сможешь понять, какой именно наследник тебе надо рассмотреть повнимательнее.
Закопайте этот сраный С++ поглубже нафиг, вот что я скажу.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Для этого он должен бы стать компилятором. Только при компиляции выясняется, корректна ли та или иная конструкция или нет. Что, собственно, с шаблонами и имеет место быть.
Почему ты просто не присобачить внешний билд-скрипт, который пишется на том же С++, принимает на вход уже разобранной АСТ-дерево и позволяет посмотреть на результат работы в текстовом виде?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Здравствуйте, T4r4sB, Вы писали:
TB>Зато Govno Compiler Collection тебе в случае опечатки в параметре шаблонной функции тебе выдаст развёрнутое эссе на тему каждой перегрузки этого шаблона, почему же он не смог тут её применить, и ты будешь не менее минуты листать это эссе, докапываясь до истины.
Да и MSVC++ не лучше.
TB>Закопайте этот сраный С++ поглубже нафиг
Весь не надо, а вот иные "продвинутые технологии" лучше бы продвигали поглубже в задницу.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Вам в Rust с его процедурными макросами. И сообщения об ошибках у компилятора Rust восхитительно подробные и ясные.
Здравствуйте, Евгений Музыченко, Вы писали:
С>>Вам в Rust с его процедурными макросами. И сообщения об ошибках у компилятора Rust восхитительно подробные и ясные.
ЕМ>Мне б совместить преимущества того и другого.
Чтобы что-то сделать с C++, нужно очень больше влияние и сообщество. Dlang не взлетел особо, а С++ не поддаётся урезанию. Чтобы воздействовать на комитет С++, нужна большая группа поддержки, поэтому агитацию за макросы надо вести на Реддите, hackernews и проч, а здесь это бессмысленно, по-моему.
Здравствуйте, Слава, Вы писали:
С>агитацию за макросы надо вести на Реддите, hackernews и проч, а здесь это бессмысленно
Да я пока не агитирую. Интересно стало, есть ли у шаблонов в их нынешнем виде какие-либо явные преимущества перед адекватными макросами (о том, что поддерживает C/C++, вообще речи нет).
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Вообще, Музыченко странный тип, он сравнивает то, что есть в плюсах(шаблоны) с какими-то мифическими макросами, которых в С++ нет. И на этом основании делает вывод — шаблоны дерьмо, а вот вымышленные макросы — гуд. При этом, по его же словам, он реально шаблонами не пользовался, представление о них имеет как свинья об апельсине и повторяет мантры всяких неосиляторов про портянки ошибок от которых у них предохранители в голове перегорают и т.д. У меня в проекте практически везде шаблоны и ничего, с приходом концепций все проблемы с неправильными типами параметоров и пр. вообще улетучились. Куча юнит-тестов перенесена в компайл-тайм. Может товарищам с шаблонофобией проверить откуда у них руки растут, может как у осьминогов — из жопы?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Помню, как в начале 90-х все пищали: "ах, шаблоны — это так круто и удобно, попрощаемся же навсегда с macro hell". Теперь мы уже много лет имеем template hell, но настолько привыкли считать, что шаблоны — это круто, что как-то даже стыдно думать об альтернативах. А ведь на обработку сотен-тысяч навороченных макросов требовались ничтожные, по нынешним временам, ресурсы, но сейчас обработка сравнимого количества шаблонов требует многократно бОльших ресурсов, а отлаживать их нередко бывает сложнее, чем макросы.
макросы очень давно существуют в common lisp и работа с ними вполне приятна. На них в частности сделали ООП (aka CLOS) в лиспе.
Если бы для С было схожее + REPL для development режима позволяющий изменять конструкции программы на лету и в частности показывать вид интерпретированных макросов, в С++ возможно не было б нужды
Помнится в колледже я писал библиотеку работы с матрицей, узнал даже про перегрузку операторов, ведь мне нужно было умножение.
Про шаблоны не знал, да вроде и не было ещё тогда их.
Тогда я думал какой взять тип элемента float или double. И сделал typedef.
Потом появилась идея заменить typedef макросом для типа и префикса перед инклюдом библиотеки, чтобы можно было одновременно пользоваться разными матрицами и не писать сто раз одно и тоже. Есть #define, есть #undef — так это можно было сделать. Не очень красиво, зато работает.
Когда я узнал про шаблоны и стал их осваивать сам (на уроке про них тогда не рассказывали), то понял — вот оно. Не надо инклюдить несколько раз один файл, а просто подставить нужный тип элемента и всё.
И не городить огород инклюдов с передифайнами. 1 строчка на дифайн префикса, 1 строчка на дифайн типа, 1 строчка на каждый инклюд. А если надо больше параметров-типов? И не забыть про андифайны после инклюда!
Вы предлагаете вернуться к макросам? Как вы решите такую задачу?
Макросы помогут скажем сделать умножение двух матриц с разными типами элемента? Если да, то покажите как.
Да хоть на любой другой задаче...
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Помню, как в начале 90-х все пищали: "ах, шаблоны — это так круто и удобно, ЕМ>...
Шёл 2022 год. Народ уже давно освоил лямбды, constexpr и вариадические шаблоны, и также вовсю начал юзать async, концепты и модули... Тем временем Евгений Музыченко занялся вопросом чем шаблоны лучше макросов
начинаю подозревать что кроме того что вы тролль
вы уже и не имеете никакого отношение к современному программированию
ну кроме тех программ которые вы написали в году так 1998, и с болью пытаетесь компилировать современным компилятором
#define MAX(x,y) (x)>(y)?(x):(y)
int val = 1;
int get_val()
{
return val++;
}
int main()
{
#ifdef MAX
printf("max %d\n",MAX(get_val(),get_val()));
#else
printf("max %d\n",std::max(get_val(),get_val()));
#endif
}
Здравствуйте, Sm0ke, Вы писали:
S>И не городить огород инклюдов с передифайнами. 1 строчка на дифайн префикса, 1 строчка на дифайн типа, 1 строчка на каждый инклюд. А если надо больше параметров-типов? И не забыть про андифайны после инклюда!
Все описанное в основном является следствием не макросов, как таковых, а отделения препроцессора от компилятора, и крайним убожеством первого.
S>Вы предлагаете вернуться к макросам?
Я предлагаю сравнить функциональнось и удобство современных шаблонов с адекватно реализованными макросами. Если Вы никогда не видели макросов, отличных от сишных, то Вам нет смысла и сравнивать.
Здравствуйте, A13x, Вы писали:
A>Если бы для С было схожее + REPL для development режима позволяющий изменять конструкции программы на лету и в частности показывать вид интерпретированных макросов, в С++ возможно не было б нужды
Внезапно, вижуалка показывает, во что раскрывается макрос, если на него навести мышку
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Элементарно. Макропроцессору, встроенному в компилятор, нетрудно оформить порожденный код в отдельный набор строк для отладчика, который кладется в БД с отладочной информацией. Ниоткуда ведь не следует, что отладчик может показывать только то, что лежит в исходных файлах.
Наверное, надо менять формат отладочной БД, и от этого куча всего поломается
Здравствуйте, удусекшл, Вы писали:
У>Внезапно, вижуалка показывает, во что раскрывается макрос, если на него навести мышку
Только если IntelliSense сработало правильно. Если обломалось (например, фатальная ошибка при компиляции), то не покажет. Придется привести текст к виду, в котором он хоть как-то компилируется, и при этом структура макроса не изменится.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я предлагаю сравнить функциональнось и удобство современных шаблонов с адекватно реализованными макросами. Если Вы никогда не видели макросов, отличных от сишных, то Вам нет смысла и сравнивать.
Конкретные примеры можно? Я же не буду искать все реализации макросов вообще во всех языках ...
Здравствуйте, Sm0ke, Вы писали:
ЕМ>>Я предлагаю сравнить функциональнось и удобство современных шаблонов с адекватно реализованными макросами. Если Вы никогда не видели макросов, отличных от сишных, то Вам нет смысла и сравнивать.
S>Конкретные примеры можно? Я же не буду искать все реализации макросов вообще во всех языках ...
Я так понимаю, что он хочет что-то типа доступа к AST, чтобы можно было писать простые функции с циклами, набивающие AST дополнительными штуками, и чтобы эти функции писались на том же C++ и исполнялись во время компиляции. Что-то такое есть в C# вроде.
Но вообще — это может быть годно только как дополнение к текущему языку и его шаблонам. Потому что если резать шаблонную магию, то придётся таких генераторов для набивки AST пачками писать. Ну а Евгений не очень в шаблоны умеет, поэтому и хочет такой велосипед с квадратными колёсами
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Помню, как в начале 90-х все пищали: "ах, шаблоны — это так круто и удобно, попрощаемся же навсегда с macro hell". Теперь мы уже много лет имеем template hell, но настолько привыкли считать, что шаблоны — это круто, что как-то даже стыдно думать об альтернативах. А ведь на обработку сотен-тысяч навороченных макросов требовались ничтожные, по нынешним временам, ресурсы, но сейчас обработка сравнимого количества шаблонов требует многократно бОльших ресурсов, а отлаживать их нередко бывает сложнее, чем макросы.
ЕМ>При этом, изрядная доля macro hell происходила лишь от того, что обработка исходника была искусственно разделена на препроцессирование и компиляцию. В начале 70-х это еще можно было как-то оправдать нехваткой ресурсов, хотя убогие возможности сишного препроцессора вряд ли могли заметно утяжелить компилятор. Имей компилятор возможность хотя бы просто выдать в сообщении об ошибке как исходную конструкцию, так и результат ее обработки макропроцессором, это свело бы на нет бОльшую часть проблем.
ЕМ>Современные компиляторы используют предкомпиляцию шаблонов, но она, по сути, не столько ускоряет компиляцию вообще, сколько снижает тормоза, создаваемые множеством многоуровневых шаблонных конструкций. И все равно оптимизатору приходится как-то систематизировать функции, чтобы объединить те, что отличаются только типами, но при этом не оформлены ни в шаблоны, ни в перегрузки.
Так исторически сложилось, что препроцессор, унаследованный от C, во первых слишком убог, во вторых, воспринимает код как текст и ничего не знает о классах и функциях. Но из-за обратной совместимости, с ним ничего не сделаешь. Мысль о том, что макросы должны быть более умными и понимать семантику языка уже давным давно приходила в голову многим, но никто толком не знал, как же это должно выглядеть.
Шаблоны изначально создавались, как простой механизм для параметризации типов. То, что с их помошью можно делать всякую магию и организовать условную компиляцию и кодогенерацию получилось совершенно случайно и для многих было неожиданным. Так получилось, что в языке уже оказалось средство, которое могло решить многие проблемы убогого препроцессора. Синтаксис шаблонов был ужасен, так как их делали для других целей, но проблема решалась сама собой, не нужно было придумывать новый метаязык и долго решать проблемы обратной совместимости. Предполагалось, что синтаксис шаблонов можно будет потихоньку доработать до чего-то более менее удобного. Но и тут оказалось все совсем не просто, не получилось и сохранить обратную совместимость и упростить синтаксис, в итоге получилось что синтаксис только усложнялся и продолжает усложняться.
ЕМ>Считается, что функциональный стиль использования шаблонов — это благо, но многие ли способны быстро разобраться в иерархии и взаимодействии шаблонов в какой-нибудь Boost? В конце концов, какая часть математиков интуитивно воспринимает факториал, как отображение множества целых чисел само на себя, или, на худой конец, как рекурсию, а не как последовательное (итеративное) произведение?
ИМХО никто так не считает, просто так получилось, а что-то серьезное менять боятся.
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Ну, вот "if constexpr", который позволяет нормально выбрать условие во время компиляции вместо жутких enable_if и SFINAE в язык все таки добавили, хотя и осилили только к 17 стандарту.
Разговоры про compile_time reflection идут давным давно, но не похоже что это скоро попадет в язык.
Вон Саттер еще давно делал доклад о всяких метаклассах: www.youtube.com/watch?v=4AfRAVcThyA
Но никто не готов на такие радикальные перемены, потому, что нет уверенности что мы не сделаем синтаксис еще более непонятным и запутанным.
Здравствуйте, удусекшл, Вы писали:
У>Я так понимаю, что он хочет что-то типа доступа к AST, чтобы можно было писать простые функции с циклами, набивающие AST дополнительными штуками, и чтобы эти функции писались на том же C++ и исполнялись во время компиляции.
Не, это было бы неоправданно сложным в реализации. А вот если бы при раскрытии макроса можно было проанализировать его параметры (типы, имена объектов, функций, константы и т.п.), и породить код, зависящий от ряда условий, то большинство конструкций, традиционно реализуемых на шаблонах, выглядело бы куда приятнее/понятнее, и было бы проще в отладке.
У>Потому что если резать шаблонную магию
Будь у языка изначально приличный макропроцессор, шаблонная магия не имела бы шансов возникнуть. Она ж возникла, по сути, от безысходности, это уже потом фанаты вроде Александреску убедили всех, что не умеющий чесать левое ухо правой ногой заслуживает порицания, если не презрения.
У>а Евгений не очень в шаблоны умеет
Евгений в шаблоны умеет, если очень надо. Но многоэтажные рекурсивные конструкции, работающие, по сути, на побочных эффектах, ему глубоко антипатичны.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>А вот если бы при раскрытии макроса можно было проанализировать его параметры (типы, имена объектов, функций, константы и т.п.), и породить код, зависящий от ряда условий, то большинство конструкций, традиционно реализуемых на шаблонах, выглядело бы куда приятнее/понятнее, и было бы проще в отладке.
Здравствуйте, Евгений Музыченко, Вы писали:
У>>Я так понимаю, что он хочет что-то типа доступа к AST, чтобы можно было писать простые функции с циклами, набивающие AST дополнительными штуками, и чтобы эти функции писались на том же C++ и исполнялись во время компиляции.
ЕМ>Не, это было бы неоправданно сложным в реализации. А вот если бы при раскрытии макроса можно было проанализировать его параметры (типы, имена объектов, функций, константы и т.п.), и породить код, зависящий от ряда условий, то большинство конструкций, традиционно реализуемых на шаблонах, выглядело бы куда приятнее/понятнее, и было бы проще в отладке.
Ну, то есть те же самые C++ шаблоны, + концепты из нового стандарта
У>>Потому что если резать шаблонную магию
ЕМ>Будь у языка изначально приличный макропроцессор, шаблонная магия не имела бы шансов возникнуть. Она ж возникла, по сути, от безысходности, это уже потом фанаты вроде Александреску убедили всех, что не умеющий чесать левое ухо правой ногой заслуживает порицания, если не презрения.
Ну, то есть, ты хотел бы, чтобы шаблоны с концептами были сразу в CFront? Ну, такое маловероятно. Думаю, никто тогда такого вообще и помыслить не мог. Побочные явления, типа SFINAE, которое использовал Александреску, были в общем-то случайно обнаружены.
Не что-то могу припомнить, в каком бы языке такое было бы сразу искаропки. Ну, может, Rust какой-нибудь. Ну, тут надо просто посмотреть на даты создания языков... И тот же раст писали люди знакомые с современными (хотя бы на тот момент) плюсами
У>>а Евгений не очень в шаблоны умеет
ЕМ>Евгений в шаблоны умеет, если очень надо. Но многоэтажные рекурсивные конструкции, работающие, по сути, на побочных эффектах, ему глубоко антипатичны.
Здравствуйте, ksandro, Вы писали:
K>из-за обратной совместимости, с ним ничего не сделаешь.
С чего бы вдруг? Есть множество способов расширения и синтаксиса, и семантики без малейшей потери совместимости.
K>Мысль о том, что макросы должны быть более умными и понимать семантику языка уже давным давно приходила в голову многим, но никто толком не знал, как же это должно выглядеть.
Так хоть бы попытались несколько раз. А то такое впечатление, что хаотично мечутся, добавляя сугубо частные возможности и закрывая столь же частные бреши, а об универсальных возможностях думают меньше всего.
K>Шаблоны изначально создавались, как простой механизм для параметризации типов. То, что с их помошью можно делать всякую магию и организовать условную компиляцию и кодогенерацию получилось совершенно случайно и для многих было неожиданным.
Это я в курсе. Но еще более неожиданным стало стремление делать на шаблонах все, что было технически возможным. А в силу пресловутой полноты оказалось, что делать на них можно вообще все без исключения. И возобладал подход "на кой совершенствовать язык, если можно нагородить пару десятков или сотен тысяч строк на шаблонах? нужно совершенствовать шаблоны!".
K>Предполагалось, что синтаксис шаблонов можно будет потихоньку доработать до чего-то более менее удобного. Но и тут оказалось все совсем не просто
Если изо всех сил держаться за функциональный подход — непросто. А если принять возможность процедурного подхода, то в любой момент можно добавить конструкций для анализа и перебора параметров, условного включения фрагментов кода, повторения похожих по виду конструкций и т.п. Такая проблема давно известна — например, даже простейшие алгоритмы, будучи реализованы в виде конечных автоматов, могут приобретать совершенно неприличный вид и изрядную сложность в отладке.
ЕМ>>Считается, что функциональный стиль использования шаблонов — это благо
K>ИМХО никто так не считает, просто так получилось
Да ну, полно приверженцев ФП, для которых любая новая функциональная конструкция — еще один шаг к божественному.
K>Ну, вот "if constexpr"
Да, хороший пример сугубо частного решения. А при грамотном подходе еще полвека назад #ifdef мог бы работать так же.
Здравствуйте, ArtDenis, Вы писали:
AD>Можно пример как это может выглядеть?
Ну вот шаблоны type traits реализованы так, что для определенных типов они явно специализированы с нужными значениями констант, а для остальных выбираются варианты по умолчанию. То есть, это устроено задом наперед, при этом установка и извлечение значений констант работает, по сути, на побочных явлениях. Если бы в языке был способ "интеллектуального" раскрытия хоть макросов, хоть шаблонов, то можно было бы проверять заданный параметром тип обычными условными конструкциями вроде #ifdef.
А если бы в языке изначально были условные конструкции, работающие на уровне компилятора (вроде __if_exists в MSVC), то из этого естественным образом вытекало бы и наличие встроенных предикатов для типов, переменных, функций, шаблонов и прочего. Вот тогда было бы одновременно и удобно, и красиво, и в реализации недорого.
Re[10]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, удусекшл, Вы писали:
У>Ну, то есть те же самые C++ шаблоны, + концепты из нового стандарта
Концепты — очередной сугубо частный костыль, чтоб, упаси боже, не нарушить священную функциональную парадигму.
У>ты хотел бы, чтобы шаблоны с концептами были сразу в CFront?
Я хотел бы, чтоб концептов не было вообще, а конструкции вроде шаблонов были еще в позднем C — хоть на основе макросов (но не традиционных, а более адекватных).
У>Думаю, никто тогда такого вообще и помыслить не мог.
Да ну, макросредства в языках появились достаточно давно, но более убогих, чем в C/C++, насколько я знаю, нигде не было и нет. А делается-то ведь примитивно до невозможности. У компилятора всегда есть вся необходимая информация о программных элементах. Добавляем простые конструкции для извлечения этой информации, и столь же простые конструкции для условной компиляции по их результатам. Все, на этом просто и изящно делается львиная доля того, что было наколхожено на шаблонах за все время их существования.
У>Побочные явления, типа SFINAE, которое использовал Александреску, были в общем-то случайно обнаружены.
Да. И само то, что их так охотно подхватили и стали продвигать, лучше всего иллюстрирует извращенный характер мышления этих людей. Это что-то вроде строительства дома из пластиковых бутылок — выглядит круто и необычно, позволяет обрести известность и прослыть гуру, но для массового применения никак не годится.
У>Не что-то могу припомнить, в каком бы языке такое было бы сразу искаропки.
Например, в ассемблере 360/370 (60-е годы) был неимоверно мощный и удобный макропроцессор, на нем можно было черта сделать, поскольку там была доступна информация о трансляции (адреса, размеры переменных и т.п.). Но вот в ЯВУ почему-то всегда так получалось, что есть либо чистый макропроцессор (на уровне абстрактных лексем), либо навороченный (и часто полуинтерпретируемый) язык, либо скудный язык и минимумом или полным отсутствием макросредств.
Здравствуйте, TailWind, Вы писали:
TW>В 99% случаев хватает виртуальных функций
Если не требуется виртуальности во время выполнения, то некоторые вещи и удобно, и экономно реализуются на шаблонах. Но с ростом сложности очень быстро растет извращенность конструкций и количество требуемых костылей. Тут главное — вовремя остановиться.
TW>- сложность понять что написал 5 лет назад на шаблонах (имел негативный опыт)
Я с некоторых пор взял за правило описывать причины выбора тех или иных подходов, решений, конструкций — или в комментариях, или отдельно. Любая мало-мальски нетипичная конструкция через несколько лет рискует показаться бессмысленной и ненужной, а при удалении/переделке лезут глюки, и тогда вспоминается, для чего было сделано именно так.
Re[11]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Как вы на макропроцессоре решите следующую задачу:?
#include <iostream>
class Out
{
public:
Out& operator << (int n);
Out& operator << (const char* pStr);
template <class T>
Out& operator << (T) = delete;
};
Out& Out::operator << (int n)
{
std::cout << n;
return *this;
}
Out& Out::operator << (const char* pStr)
{
std::cout << pStr;
return *this;
}
int main()
{
Out o;
int x = 1;
o << x << "\n";
unsigned int u = 0xFFFFFFFF;
o << u << "\n";
o << "\n the end \n";
return 0;
}
У>Я так понимаю, что он хочет что-то типа доступа к AST, чтобы можно было писать простые функции с циклами, набивающие AST дополнительными штуками, и чтобы эти функции писались на том же C++ и исполнялись во время компиляции. Что-то такое есть в C# вроде.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>С чего бы вдруг? Есть множество способов расширения и синтаксиса, и семантики без малейшей потери совместимости.
С того, что тут придется создавать еще один метаязык, который должен как-то не испортить текущие шаблоны и макросы, мне кажется никто не готов взять на себя такую огромную работу. С++ и так уже переусложнен. Проблема в том, что это надо еще согласовать в коммитете по стандартизации. Никто за это не возьмется.
ЕМ>Так хоть бы попытались несколько раз. А то такое впечатление, что хаотично мечутся, добавляя сугубо частные возможности и закрывая столь же частные бреши, а об универсальных возможностях думают меньше всего.
Так пытаются, есть всякие предложения по reflection и обсуждают идеи метаклассов, но когда от абстрактных идей переходят к более менее конкретной логике, то понимают, что не осилят...
ЕМ>Это я в курсе. Но еще более неожиданным стало стремление делать на шаблонах все, что было технически возможным. А в силу пресловутой полноты оказалось, что делать на них можно вообще все без исключения. И возобладал подход "на кой совершенствовать язык, если можно нагородить пару десятков или сотен тысяч строк на шаблонах? нужно совершенствовать шаблоны!".
Тут соглашусь, то, что с помощью шаблонов можно уже сейчас делать всякие прикольные штуки уже сейчас, а не ждать нового стандарта больше 10 лет, было для многих откровением. Поэтому на шаблонах все и стали делать.
Потом народ начал осознавать, что как-то слишком все переусложняется, но нормального другого решения пока так никто и не предложил. Нет никакой гарантии, что новый метаязык, который может быть когда-нибудь заменит шаблоны будет проще.
ЕМ>Если изо всех сил держаться за функциональный подход — непросто. А если принять возможность процедурного подхода, то в любой момент можно добавить конструкций для анализа и перебора параметров, условного включения фрагментов кода, повторения похожих по виду конструкций и т.п. Такая проблема давно известна — например, даже простейшие алгоритмы, будучи реализованы в виде конечных автоматов, могут приобретать совершенно неприличный вид и изрядную сложность в отладке.
Только вот примеров такого успешного внедрения мейнстрим в языки подобных фич, как-то не видно. Говорят в Расте что-то похожее есть, надо будет как-нибудь глянуть как будет время. А больше вроде нигде, все только в runtime.
Дело не в функциональном стиле, дело в том, что никому не хотелось добавлять еще один метаязык к существующим уже шаблонам и препроцессору.
ЕМ>Да ну, полно приверженцев ФП, для которых любая новая функциональная конструкция — еще один шаг к божественному.
У ФП, есть много преимуществ, например лучшее распараллеливание, лучшие возможности для ленивых вычислений и др. Но какие же реальные плюсы преимущества есть от ФП в шаблонном метапрограммировании. Просто других вариантов для С++ нет. И никто не осиливает сделать. Поэтому пользуются тем, что есть.
ЕМ>Да, хороший пример сугубо частного решения.
Ну, не все сразу. Вот когда-нибудь придумают синтаксис для compile-time списка разнотипных аргументов, и добавят "constexpr for", и будет счастье!
ЕМ>А при грамотном подходе еще полвека назад #ifdef мог бы работать так же.
Мне кажется тогда никто серьезно не задумывался о метапрограммировании... Считали что препроцессора достаточно.
Re[14]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>Как вы на макропроцессоре решите следующую задачу:? ЕМ>В чем именно заключается задача?
Запретить неявное преобразование типа.
ЕМ>И объем этого кода точно меньше, чем ее словесное описание?
Слова не точны, а код... Этот код хорош тем, что он не компилируется.
Здравствуйте, Евгений Музыченко.
Макросы, объединенные с компилятором, это уже не просто макросы, а полноценные языковые конструкции. В которых, наверняка, будут и перегрузки, и рекурсия, и вариадики и прочие навороты. И все эти навороты нужно будет как-то записывать и поддерживать. Поэтому, противопоставляя одно другому, вы должны точно очертить, в чем принципиально "хорошие" макросы будут отличаться от текущих шаблонов. Простота и мощь текущих макросов, конечно, заманчива и кажется, что их "чуть чуть развить" и сразу они "похоронят" "переусложнённые" шаблоны. Но это только так кажется.
Здравствуйте, ksandro, Вы писали:
K>С того, что тут придется создавать еще один метаязык, который должен как-то не испортить текущие шаблоны и макросы, мне кажется никто не готов взять на себя такую огромную работу.
Я ж не говорю, что это нужно делать сейчас — поздно, поезд давно уже идет под откос. А вот лет 20-30 назад, когда уже было достаточно хорошо видно, что template hell будет покруче macro hell, впору было задуматься.
K>Так пытаются, есть всякие предложения по reflection и обсуждают идеи метаклассов, но когда от абстрактных идей переходят к более менее конкретной логике, то понимают, что не осилят...
Во многом — потому, что пытаются удержаться в рамках принятой парадигмы. А в этом нет смысла — язык давно потерял всякое подобие стройности и логичности, и уже почти нет разницы, с какой стороны и в каком виде громоздить новое.
K>то, что с помощью шаблонов можно уже сейчас делать всякие прикольные штуки уже сейчас, а не ждать нового стандарта больше 10 лет, было для многих откровением. Поэтому на шаблонах все и стали делать.
И стало это сильно напоминать известный анекдот.
K>Вот когда-нибудь придумают синтаксис для compile-time списка разнотипных аргументов, и добавят "constexpr for", и будет счастье!
Да, с новым костылем, столь же частным, сколь и остальные.
ЕМ>>еще полвека назад #ifdef мог бы работать так же.
K>Мне кажется тогда никто серьезно не задумывался о метапрограммировании...
О метапрограммировании и задумывались, и пробовали еще раньше.
K>Считали что препроцессора достаточно.
Подозреваю, что в основном люди просто не видели нормальный реализаций макропроцессора.
Re[15]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Went, Вы писали:
W>Макросы, объединенные с компилятором, это уже не просто макросы, а полноценные языковые конструкции.
Ну да. Это средства, позволяющие компилятору при обработке исходного кода порождать новый исходный код, и тут же его обрабатывать.
W>В которых, наверняка, будут и перегрузки, и рекурсия, и вариадики и прочие навороты.
Зачем там перегрузки? Каково их возможное применение? Рекурсия там была бы обязательно, но контролируемая более явно и точно, нежели в шаблонах. "Вариадики" в таких конструкциях не нужны — это костыль исключительно для функционального стиля. Представьте, что в сишную main вместо argc/argv передавались бы "вариадики".
W>вы должны точно очертить, в чем принципиально "хорошие" макросы будут отличаться от текущих шаблонов.
Я ж вроде описал — более естественным и понятным способом развертывания, обработки параметров, управления порождением кода. Тем же, чем любой процедурный язык отличается от любого функционального. Математические задачи, моделирование и подобное на ФЯ решаются удобно и изящно, но как доходит до реализации обычного последовательного алгоритма, так сразу начинаются пляски.
W>Простота и мощь текущих макросов
У Вас слишком много ошибок в словах "примитивность" и "убожество".
W>кажется, что их "чуть чуть развить" и сразу они "похоронят" "переусложнённые" шаблоны.
Повторю: речь не о том, чтобы сейчас заменить шаблоны "продвинутыми макросами" — это очевидно невозможно без создания новой версии языка. Речь о том, что сперва был реализован примитивный и неудобный препроцессор, затем он заботливо сохранялся два десятка лет, а затем, "для избавления от macro hell", были созданы шаблоны, которые создали hell почище прежнего.
Re[17]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Зачем там перегрузки? Каково их возможное применение? Рекурсия там была бы обязательно, но контролируемая более явно и точно, нежели в шаблонах. "Вариадики" в таких конструкциях не нужны — это костыль исключительно для функционального стиля.
Говоря о перегрузках, я имел в виду ветвление в зависимости от типов передаваемых параметров. Например, я хочу, чтобы для все целых генерировался один код, для дробных — другой. Это не совсем перегрузка, но близко. В чем бы ваши макросы принципиально отличались от шаблонов? Процедурным подходом? Вы уверены, что он проще и выразительней? И, главное, вы уверены, что он также расширяем? Вот написал я чудо-макрос, который для плавающих делает одно, а для целых — другое. А уже в коде ниже потребовалось добавить исключение, что для булевых нужно делать третье. Как бы я это сделал? "Расширил" бы макрос? "Заместил" бы макрос? Или специализировал? И где тогда процедурный подход?
ЕМ>Представьте, что в сишную main вместо argc/argv передавались бы "вариадики".
Вы точно понимаете, что такое вариадики?
ЕМ>Я ж вроде описал — более естественным и понятным способом развертывания, обработки параметров, управления порождением кода. Тем же, чем любой процедурный язык отличается от любого функционального. Математические задачи, моделирование и подобное на ФЯ решаются удобно и изящно, но как доходит до реализации обычного последовательного алгоритма, так сразу начинаются пляски.
Лучше бы с примерами. А то получается "за всё хорошее", но без конкретики.
ЕМ>У Вас слишком много ошибок в словах "примитивность" и "убожество".
В своих проектных рамках, макросы просты и мощны. Если за них вылазить, имитируя метапрограммирование, начинается hell.
ЕМ>Повторю: речь не о том, чтобы сейчас заменить шаблоны "продвинутыми макросами" — это очевидно невозможно без создания новой версии языка. Речь о том, что сперва был реализован примитивный и неудобный препроцессор, затем он заботливо сохранялся два десятка лет, а затем, "для избавления от macro hell", были созданы шаблоны, которые создали hell почище прежнего.
Нет, hell в шаблонах начинается тогда, когда вы вылазите в них за проектные рамки. Это касается любой технологии, любой части языка. Если делать на шаблонах то, ради чего их вводили, а не всякие boost::mpl, то все чики-пуки. И без шаблонов можно создать hell на goto, на switch, UB hell, hell при написании истинно-кросплатформенного кода, функциональный лямбда-hell и т.п.
Re[18]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
NB>>как это будут выглядеть на твоих макросах?
ЕМ>В этом примере is_signed вернет false, и assert обломается. А чего хотелось-то?
на уровне main (и на уровне lib2 по желанию) иметь возможность сделать так, чтобы возвращало true, очевидно
шаблоны такое сделать позволяют, а макросы?
Re[19]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, night beast, Вы писали:
NB>на уровне main (и на уровне lib2 по желанию) иметь возможность сделать так, чтобы возвращало true, очевидно
Я ж привел самый простейший пример для иллюстрации. В нормальной реализации, коли уж есть стандартное условие "-1 < 0", как раз is_signed и is_unsigned стоило бы сделать через него. Но еще правильнее следовало делать такое через атрибуты типов, задаваемые непосредственно в определении класса и/или выводимые из набора определенных операций.
Re[20]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
NB>>на уровне main (и на уровне lib2 по желанию) иметь возможность сделать так, чтобы возвращало true, очевидно
ЕМ>Я ж привел самый простейший пример для иллюстрации. В нормальной реализации, коли уж есть стандартное условие "-1 < 0", как раз is_signed и is_unsigned стоило бы сделать через него. Но еще правильнее следовало делать такое через атрибуты типов, задаваемые непосредственно в определении класса и/или выводимые из набора определенных операций.
а я привел пример, когда это не работает.
lib2 ничего не знает про lib1 и необходимые для него атрибуты типов.
а специализация позволяет эти атрибуты задать не влезая в определения существующих типов.
подобного эффекта ты бы мог добиться, добавив для своих макросов перегрузку. но тогда у тебя получились бы те же шаблоны, вид сбоку.
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>Запретить неявное преобразование типа. ЕМ>Для этого не нужен макропроцессор. Нужны языковые средства задания допустимых правил преобразования.
Что ж, вот вам и ответ на вопрос темы: шаблоны позволяют сделать то, что макропроцессору не по силам.
Здравствуйте, Went, Вы писали:
W>В чем бы ваши макросы принципиально отличались от шаблонов? Процедурным подходом? Вы уверены, что он проще и выразительней?
Для операций, которые проще описываются последовательностью действий, а не подобием или рекурсией — безусловно. А подобие/рекурсия там тоже реализуются достаточно просто.
W>вы уверены, что он также расширяем? Вот написал я чудо-макрос, который для плавающих делает одно, а для целых — другое. А уже в коде ниже потребовалось добавить исключение, что для булевых нужно делать третье. Как бы я это сделал? "Расширил" бы макрос? "Заместил" бы макрос? Или специализировал?
Можно было бы предусмотреть любые удобные варианты. Такое впечатление, что Вы рассматриваете любые макросы, как предельно тупые конструкции, которые должны раскрываться сразу же, как только обнаружен соответствующий идентификатор. Но ничто не вынуждает рассматривать их именно так. По сути, шаблоны — тоже вид макросов, но обрабатываемых более сложным образом. Основная проблема, на мой взгляд, состоит в том, что шаблоны, с их функционально-регулярной парадигмой, неочевидностью и чрезмерной сложностью, противопоставлены традиционным макросам, которые убоги и примитивны. Они находятся на крайних участках шкалы возможностей, а между ними — пусто.
ЕМ>>Представьте, что в сишную main вместо argc/argv передавались бы "вариадики".
W>Вы точно понимаете, что такое вариадики?
Точно понимаю. Именно поэтому и предлагаю представить себе реализацию командно-строковой утилиты со сколько-нибудь сложным форматом параметров, в которую вместо argc/argv передаются "пакеты параметров", раскрываемые регулярным образом. А потом представьте, что кто-то таки осилил написать такую утилиту, и теперь Вам требуется ее доработать, добавив еще пару-тройку возможных параметров, формат которыых не получается уложить в выбранную систему.
W>В своих проектных рамках, макросы просты и мощны. Если за них вылазить, имитируя метапрограммирование, начинается hell.
Что значит "имитируя"? Любые макросы по определению предназначены для метапрограммирования.
W>hell в шаблонах начинается тогда, когда вы вылазите в них за проектные рамки.
При выбранном пути развития языка его было невозможно избежать. Как только появились самые первые неочевидные, "заумные" конструкции на шаблонах, лидерам разработки языка нужно было бегом дорабатывать ядро, чтобы эти конструкции могли быть реализованы по-человечески. Но они сами вдохновились этой идеей, и благословили применение шаблонов для всего, на что они технически способны (а способны они, как мы помним, вообще на все). С этого момента hell стал неизбежным.
W>И без шаблонов можно создать hell на goto
Так его успешно и создавали до тех пор, пока Дейкстра сотоварищи не показали, что любая программа с goto может быть преобразована в структурированную, и выглядеть при этом или лучше, или не хуже. До этого сторонники goto успешно защищались, приводя все более навороченные схемы, и утверждая "а вот этого вы на своем Алголе не сделаете".
Пока в ядре языка не будет средств, позволяющих удобно и эффективно делать то, что сейчас принято делать на хитровыгнутых шаблонах — hell будет только умножаться.
Здравствуйте, Евгений Музыченко, Вы писали:
W>>Вы точно понимаете, что такое вариадики? ЕМ>Точно понимаю. Именно поэтому и предлагаю представить себе реализацию командно-строковой утилиты со сколько-нибудь сложным форматом параметров, в которую вместо argc/argv передаются "пакеты параметров", раскрываемые регулярным образом. А потом представьте, что кто-то таки осилил написать такую утилиту, и теперь Вам требуется ее доработать, добавив еще пару-тройку возможных параметров, формат которыых не получается уложить в выбранную систему.
Не понимаю. Набор входящих параметров — это абсолютно динамические данные очень свободной формы. Вариадики — наборы типов, строго определенных в момент компиляции. Как в момент компиляции можно предугадать, какие данные передадутся в main? Как вывести их тип?
ЕМ>Что значит "имитируя"? Любые макросы по определению предназначены для метапрограммирования.
Использование С-макросов для кодогенерации — это hell и выход за проектные рамки. Макросы здорового человека используются только для управления процессом компиляции.
По поводу прочего — вы говорите о "хороших макросах" как о чем-то, обладающим всей мощью шаблонов, но без их недостатков. Я бы хотел понять, в чем ожидается их принципиальная разница с шаблонами?
Re[21]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, night beast, Вы писали:
NB>а я привел пример, когда это не работает.
Так для любой возможности можно привести пример, когда она не работает, или бесполезна, или неудобна.
NB>а специализация позволяет эти атрибуты задать не влезая в определения существующих типов.
Для навешивания атрибутов на существующие типы тоже давно требуются языковые средства. Они крайне просты в реализации, но их не торопятся добавлять, поскольку того же можно достичь шаблонной магией. Через задницу, боль и геморрой, но технически можно. Именно поэтому тянуть будут до последнего.
NB>подобного эффекта ты бы мог добиться, добавив для своих макросов перегрузку. но тогда у тебя получились бы те же шаблоны, вид сбоку.
Так ведь шаблоны, по сути, и есть параметризованные макросы. И шаблоны, и тот вид "макросов", о котором я говорю, обрабатываются в контексте программы, а не тупых лексем. Понятное дело, что и там, и там возможна перегрузка и подобные приемы.
Здравствуйте, Went, Вы писали:
W>Набор входящих параметров — это абсолютно динамические данные очень свободной формы. Вариадики — наборы типов, строго определенных в момент компиляции. Как в момент компиляции можно предугадать, какие данные передадутся в main? Как вывести их тип?
Никакие типы выводить не нужно. Я предложил сравнить процесс обработки (во время компиляции) шаблона, в который передается переменное количество параметров, с процессом обработки (во время выполнения) кода main, в который параметры передавались бы таким же регулярным способом, что и параметры в шаблон. Реализация утилит, получающих наборы однотипных параметров разной длины, была бы несложной, зато реализация утилит с мало-мальски сложной командной строкой усложнилась бы неимоверно, а то и вовсе стала невозможной без написания отдельной процедуры для каждого набора. Именно это мы и имеем в существующем подходе к variadic.
W>Использование С-макросов для кодогенерации — это hell и выход за проектные рамки. Макросы здорового человека используются только для управления процессом компиляции.
Откуда Вы это взяли? Будь макросы предназначены исключительно для задания параметров-констант, их бы изначально ограничили до чисел, строк и идентификаторов.
W>вы говорите о "хороших макросах" как о чем-то, обладающим всей мощью шаблонов, но без их недостатков. Я бы хотел понять, в чем ожидается их принципиальная разница с шаблонами?
Да ради бога, можно вообще забыть слово "макрос", и говорить исключительно о шаблонах. Если сделать возможным использование в коде шаблона условных и циклических конструкций, позволяющих анализировать как вид переданных параметров, так и их роль в программе — получится то же самое. Собственно, адекватные макропроцессоры делают именно это.
Re[22]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
NB>>подобного эффекта ты бы мог добиться, добавив для своих макросов перегрузку. но тогда у тебя получились бы те же шаблоны, вид сбоку.
ЕМ>Так ведь шаблоны, по сути, и есть параметризованные макросы. И шаблоны, и тот вид "макросов", о котором я говорю, обрабатываются в контексте программы, а не тупых лексем. Понятное дело, что и там, и там возможна перегрузка и подобные приемы.
мне вот, например, глядя на твое определения макроса, совсем непонятно, как туда перегрузку добавить.
покажешь?
Re[23]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, night beast, Вы писали:
NB>вроде это ты макросы продаешь
Я "продаю" не макросы, а идею. А главная проблема понимания — в том, что в сознании большинства программистов на C/C++ к термину "макрос" гвоздями прибито тупое, чисто лексическое преобразование, и при попытке представить себе любое другое, восприятие столь же прочно цепляется за "шаблон".
я вообще слабо понимаю подобную тональность в темах языкостроения. в С++ практиках редко бывает что-то особенно выделенное, особенно "vs", как правило для практической архитектурной задачи выбираются комбинированные решения. что на макро положили, что не шаблоны. Отличие макро от templates сугубо в том, что макро не попадают в АСТ, туда попадает С++, а препроцессор к языку (его ситаксису) не относится. Потому еслои ж и ратовать за макро, то я бы предложил внедрять их именно в АСТ, и вообще расширять до грамматик_о_ориентированного подхода, когда можно парсить
#define PARSE_TOKENS(txt) get_tok : token txt | txt token | token
etc' а то текущие костыли вида на базе __VA_ARGS__ мягко говоря напрягают
ЕМ>Считается, что функциональный стиль использования шаблонов — это благо, но многие ли способны быстро разобраться в иерархии и взаимодействии шаблонов в какой-нибудь Boost?
бывает, что ничего другого просто не остается, и приходится разбираться.
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
для этого надо внедрять препроцессор в АСТ, в противном случае он костылизуется до безобразия как баш, и судить о стандартизации (как и сейчас ведь те же итерации внутри макро по параметрам происходят в gcc MSVC и тд по разному) А если тащить их в АСТ, то это уже dsl
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, дев.с.оффером, Вы писали:
ДСО>>если и ратовать за макро, то я бы предложил внедрять их именно в АСТ
ЕМ>Если прочитать исходное сообщение
внимательно, то даже без чтения моих последующих разъяснений обнаружится, что именно это и предлагалось.
ЕМ>Определенно, понятия "макрос" и "макропроцессор" у подавляющего большинства накрепко прибиты гвоздями к убогому сишному препроцессору.
Вы простите, но я увидел войну. вы на стороне макросов против шаблонов. Чем, честно говоря, можно так заказать — запугиваете. Мне шаблоны оч нравятся .. в философском ткскть контексте.
а именно "что угодно во что угодно" — абстракция без которой мне не видится сейчас AI language
struct any { template <typename T> opreator T(); };
разве можно пугать отбором этого ...
а вот с раширением макро до грамматик я сршенно согласен. более того я немного ранее писал здесь .. http://rsdn.org/forum/cpp/8162357.1
после моей извращенной часто практики, где хватаются за все, получается в препроцессоре — делаешь в препроцессоре, получается в шаблонах — вперед. Я вот одного не понимаю, че все пристали к этому бедному препроцессору, хорошая вещь, там столько хороших и ценных практик, что... а — давайте засунем его в АСТ, прям вот не только в llvm. А что ??
Здравствуйте, T4r4sB, Вы писали:
TB>Закопайте этот сраный С++ поглубже нафиг, вот что я скажу.
да давайте уже закопаем это IT все вместе целиком. Вы думаете с вами цацкаться будут в ИИ ? А оно скоро вот к вам притопает прямо вот сядет рядом в виде статического анализа, и читай те эссе ..
практика показывает, что видеть ты научишься достаточно быстро. И там, где народ будет паром из мозгов брызгать, ты даже эти шаблоны ни разу не задебажишь. от поверь ...
мне коллеги говорили нетривиальный код на то, где я писал без вчитывания в эти эссе ведь понятно, что это железное )) от тебя хочет. не понимаю че вы все орете )) этож интересно ..
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Да я пока не агитирую. Интересно стало, есть ли у шаблонов в их нынешнем виде какие-либо явные преимущества перед адекватными макросами (о том, что поддерживает C/C++, вообще речи нет).
как вы не поймете, макро это — макро. а шаблоны это — щаблоны.
1. начнем еще с ассемблера да ? автоподстановка, нас с детства так учили, что такое макро. Оно так в си и задумывалось — просто генерация кода (именно генерация кода как текста) по предоставленным "шаблонам".
мы доросли до понимания, что макро либо снесут (по причине того, что оно в АСТ не попадает), либо расширят до чего-то более менее попадающего в стандарт (а не так как сейчас башеподобная кустарщина, "куда хочу так и работаю куда то втуда"), либо таки порежут. таковы тенденции
2. возмущаться плюсами можно и даже нужно, но не сильно — мешает работать. лучше сыграй на контрабасе, когда злишься, и через минуту мозговой штурм захватит тебя с такой силой, что шаблоны разлетаться будут как щепки ...
и ты поймешь что шаблоны, что контробас, что макро — инструменты для тебя любимого ) иди играйся .. ) оно прикольно. нагнешь себя любимого, потом и макро с шаблонами подогнутся.
Здравствуйте, ksandro, Вы писали:
K>ИМХО никто так не считает, просто так получилось, а что-то серьезное менять боятся.
ЕМ>>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
K>Ну, вот "if constexpr", который позволяет нормально выбрать условие во время компиляции вместо жутких enable_if и SFINAE в язык все таки добавили, хотя и осилили только к 17 стандарту. K>Разговоры про compile_time reflection идут давным давно, но не похоже что это скоро попадет в язык.
это потому как коммюнити слишком пассивное, и вместо консолидированного мнения выражают общее недовольство шаблонами. аля а давайте закопаем IT, все кому не нравится С++.
с моей точки зрения ct reflection уже вполне реальность, просто слишком оно коммерчески как бе так сказать. в общем если говорить серьезно
то это же прямой шаго к современной архитектуре в рамках smart solutions, кто вам такое бесплатно в стандарт вольет. всер ешается велосипедами. к примеру могу показать бранч где ребятки на llvm уже предложили compile time reflection делали точно для сових нуждд. еще лет 10-12 назад, как тут еще ремарк показывал, ну и ваш покроный слугаЮ, тоже имее тсвой солюшин по регистрации типов и по ct reflection. вещь оч удобная если отложить отдельно (чтобы не пересобиралась) для генерации инфарстуруктурных тестов, констрейнтов ..и все дешево во время компиляции.
K>Вон Саттер еще давно делал доклад о всяких метаклассах: K>www.youtube.com/watch?v=4AfRAVcThyA
K>Но никто не готов на такие радикальные перемены, потому, что нет уверенности что мы не сделаем синтаксис еще более непонятным и запутанным.
П.С. вы ка-то не совсем поняли Евгения .. )) я частично с ним согласен, и вот за раширения макро до грамматик
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>А если бы в языке изначально были условные конструкции, работающие на уровне компилятора ...
AD>Просто хочется увидеть примеры кода как всё это может выглядеть для некоторых случаев
ок
на )) я компайл тайм регекспы писал .. точно знаю, чего мне не хватает поговорим ?
П.С и вот это оно может быть скомпилировано, и запущено ... ))не ну ессно мне влом, но факт — оно запускалось.
вы пытаетесь критиковать живой код. а именно макро развиваются, и все развивается но в lazy как только критическая масса потребителей просят, и коммерчески это не невыгодно участникам рынка так оно в и впиливается к 20-му стандарту впливают __VA_OPT__ таки возможно оно поможет .. надо смотреть, что из этого выйдет. велкам в практику ))
Some compilers do allow C++20 support but do not implement the full
__VA_OPT__ support yet
так я думаю, что ct reflection не потому, что не могут. а потому, что не хотят я сейчас таки найду бранч где ребятки в boost гугл группе по SG7 в llvm реализовывали довольно уже подробно. было весьма интересно посмтреть
работать с этим не пробовал, т.к.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>При этом, изрядная доля macro hell происходила лишь от того, что обработка исходника была искусственно разделена на препроцессирование и компиляцию. В начале 70-х это еще можно было как-то оправдать нехваткой ресурсов, хотя убогие возможности сишного препроцессора вряд ли могли заметно утяжелить компилятор. Имей компилятор возможность хотя бы просто выдать в сообщении об ошибке как исходную конструкцию, так и результат ее обработки макропроцессором, это свело бы на нет бОльшую часть проблем.
В начале 70-х компилятор Си работал на PDP/11, машине с 16-битным адресным пространством. В лучшем случае, компилятору было доступно 64К для его собственного кода и 64К для данных. При этом он был достаточно умен, чтобы скомпилировать ядро первого UNIX или свой собственный текст. Сейчас в такую модель памяти не во всякой среде программирования "Hello, world!" поместится
ЕМ>Считается, что функциональный стиль использования шаблонов — это благо, но многие ли способны быстро разобраться в иерархии и взаимодействии шаблонов в какой-нибудь Boost? В конце концов, какая часть математиков интуитивно воспринимает факториал, как отображение множества целых чисел само на себя, или, на худой конец, как рекурсию, а не как последовательное (итеративное) произведение?
У C++ внутри два языка программирования, совершенно разных по стилю и парадигме. Один — сам C++, классический процедурно-императивный язык в стиле Си с классами. Другой — язык темплейтов, строго функциональный, с ленивой моделью вычисления и автовыводом типов, этакий Haskell с уродским синтаксисом.
Я думаю, многие проблемы C++ нас бы не коснулись, если бы язык темплейтов существовал бы в той же парадигме, в которой сделан сам C++.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Никакие типы выводить не нужно. Я предложил сравнить процесс обработки (во время компиляции) шаблона, в который передается переменное количество параметров, с процессом обработки (во время выполнения) кода main, в который параметры передавались бы таким же регулярным способом, что и параметры в шаблон. Реализация утилит, получающих наборы однотипных параметров разной длины, была бы несложной, зато реализация утилит с мало-мальски сложной командной строкой усложнилась бы неимоверно, а то и вовсе стала невозможной без написания отдельной процедуры для каждого набора. Именно это мы и имеем в существующем подходе к variadic.
Понял. Но у шаблонной кодогенерации и у обработки агрументов main разная цель. Записать тело класса, полученного при обработке шаблонных параметров, в процедурном стиле — это же жесть в подавляющем большинстве случаев.
ЕМ>Откуда Вы это взяли? Будь макросы предназначены исключительно для задания параметров-констант, их бы изначально ограничили до чисел, строк и идентификаторов.
Я это взял из многолетней практики и опыта других программистов. Как только начинаем передавать в макросы сложные параметры, а особенно параметры — код, или макрос сам разворачивается в сложный код, начинается ботва.
ЕМ>Да ради бога, можно вообще забыть слово "макрос", и говорить исключительно о шаблонах.
Прочитайте название темы, а теперь ваше сообщение. Никаких противоречий?
ЕМ>Если сделать возможным использование в коде шаблона условных и циклических конструкций, позволяющих анализировать как вид переданных параметров, так и их роль в программе — получится то же самое. Собственно, адекватные макропроцессоры делают именно это.
Итерировать переданные параметры в цикле? что-то типа constexpr for? Ну, может, скоро и будет. Но ничего волшебного он не даст, потому что задача шаблона — генерировать код, а средств генерировать код в подобной манере С++ не предоставляет (без выхода за проектные рамки). Как раз тут бы и понадобились именно макросы, которые могли бы ижектировать код, рассчитанный подобной функцией, в тело текста программы. Может быть, вы про это? Именно про способ генерации кода, а не про способы анализа передаваемых параметров.
Re[26]: Чем современные шаблоны лучше макросов? :)
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, night beast, Вы писали:
NB>>вроде это ты макросы продаешь
ЕМ>Я "продаю" не макросы, а идею.
Идея — ничто, реализация — всё. Идея без хотя бы MVP ничего не стоит. Тем более, что ты даже не идею продаешь, а какие-то абстрактные рассуждения. Ни на один вопрос ты не можешь в ответ показать, как бы выглядело удовлетворяющее тебя решение.
ЕМ>А главная проблема понимания — в том, что в сознании большинства программистов на C/C++ к термину "макрос" гвоздями прибито тупое, чисто лексическое преобразование, и при попытке представить себе любое другое, восприятие столь же прочно цепляется за "шаблон".
У тебя какие-то странные представления о большинстве программистов. А фантазировать — все горазды, а вот проиллюстрировать свои фантазии — это уже мало кто может. И ты тоже.
A>Если бы для С было схожее + REPL для development режима позволяющий изменять конструкции программы на лету и в частности показывать вид интерпретированных макросов, в С++ возможно не было б нужды https://www.youtube.com/watch?v=qQBpiaHXsWM
Как много веселых ребят, и все делают велосипед...
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Шаблоны это и есть приличный макропроцессор, объединенный с компилятором.
— А вы кто?
— Я женщина вашей мечты!
— Да? Но я не о такой мечтал!
— А сбылась такая!
Как много веселых ребят, и все делают велосипед...
Здравствуйте, ArtDenis, Вы писали:
ЕМ>>Помню, как в начале 90-х все пищали: "ах, шаблоны — это так круто и удобно, ЕМ>>...
AD>Шёл 2022 год. Народ уже давно освоил лямбды, constexpr и вариадические шаблоны, и также вовсю начал юзать async, концепты и модули... Тем временем Евгений Музыченко занялся вопросом чем шаблоны лучше макросов
У кого это была статистика что ~40% проектов на C++ имеют запрещённые исключения? И гугл тут впереди планеты всей по объёму кода с такими правилами.
Какие "async, концепты и модули"? Сколько кода с ними написано? 1%? 0.1%? 0.01%?
Я вот тут наблюдаю один вполне себе серьёзный важный проект. Уровень — C с классами. Люди — умеют свою тематику, серьёзный телеком. Геттер вида string getX() { return x_; } где "string x_"; — норма. А рядом вдруг uint8& getY() { return y_; } Const и noexcept, понятно, у обоих не стоит. Впрочем, поскольку это всё в конфигурировании (а не в hot path), всем пофиг.
Реально, "широкие народные массы" сейчас в районе C++11, не сильно выше.
Здравствуйте, netch80, Вы писали:
N>Реально, "широкие народные массы" сейчас в районе C++11, не сильно выше.
Ну я могу судить по себе только. Если новая фича что-то даёт какие-то улучшения (код проще, выразительнее, сильно короче, сильно быстрее, меньше копипасты и т.п.), то она начинает постепенно задействоваться, как только она попадает в компилятор в стабильном состоянии.
Права, недавно был в щенячем восторге от плюсового async (который мне бы пригодился в прошлом проекте ещё много лет назад). Но когда понял, что кроме удобства написания кода, он ещё даёт возможность расстреливать себе ноги автоматными очередями, загрустил и начал смотреть в сторону раста
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, netch80, Вы писали:
N>>Реально, "широкие народные массы" сейчас в районе C++11, не сильно выше.
AD>Ну я могу судить по себе только.
Ну вот это и ошибка, увы. Мы тут все оказываемся достаточно умными, чтобы сделать качественно. Это не хвастовство, увы, это констатация.
Вот на одном проекте из текущих у народа в коде дикая смесь из: табов и пробелов; LF и CRLF; почти все стили форматирования... ну и работают кто под Unix, кто под Windows, хотя целевая платформа Linux. В результате мерж оказывается почти неподъёмной задачей, что убивает кучу других параметров качества. Надо было перенести код на другую ветку без самого git (почему — это отдельный вопрос). Я на линуксе поставил core.autocrlf=true и в результате git apply прошёл, а у коллеги на Windows в тех же условиях git apply просто молча показывает "хозяин, тут делать нечего, изменений 0". В результате я ему переслал свой результат мержа (толстым архивом). Было бы больше времени, я бы поискал, почему так, но сейчас просто не до того. Ставлю вопрос форсировать политику (правилом в Jenkins), но по текущей ситуации его наверно решат через год...
Ну и код (рядом писал) в духе string getX() { return x_; } — норма.
Тем не менее проект движется, потому что 1) люди честно работают (не виноваты, что эффективность на порядок меньше нормальной, но не мухлюют) и 2) ПМы умеют в SMART или аналог.
AD> Если новая фича что-то даёт какие-то улучшения (код проще, выразительнее, сильно короче, сильно быстрее, меньше копипасты и т.п.), то она начинает постепенно задействоваться, как только она попадает в компилятор в стабильном состоянии.
Ага, а в опциях компиляции -std=c++11 и менять его не дают, потому что неизвестно, что взорвётся. Переключение на стандарт повыше это действие отдельно планируемое между ключевыми релизами и должно быть очень хорошо обосновано.
"Постепенно" — да, задействуется. Где-то в новых проектах, где-то таки убеждают догнать... но типовая 10-летняя инерция говорит, что только сейчас можно говорить, что C++11 вошёл в действительно массовое использование. И то — см. выше про исключения.
AD>Права, недавно был в щенячем восторге от плюсового async (который мне бы пригодился в прошлом проекте ещё много лет назад). Но когда понял, что кроме удобства написания кода, он ещё даёт возможность расстреливать себе ноги автоматными очередями, загрустил и начал смотреть в сторону раста
N>Я вот тут наблюдаю один вполне себе серьёзный важный проект. Уровень — C с классами. Люди — умеют свою тематику, серьёзный телеком.
Что значит "умеют"? Вызубрили порядок передачи пакетов и значения их полей при подключении клиентского устройства к провайдерскому оборудованию?
N>Геттер вида string getX() { return x_; } где "string x_"; — норма. А рядом вдруг uint8& getY() { return y_; } Const и noexcept, понятно, у обоих не стоит. Впрочем, поскольку это всё в конфигурировании (а не в hot path), всем пофиг.
Дэ, видал C++-код, написанный так называемыми "экспертами в своей области". Вполне реально было увидеть что-нибудь вроде:
так они уже достаточно допилены чтобы этот пример написать достаточно компактно, а в стандартной библиотеке так не пишут потому что:
1. она должна поддерживать и более старые стандарты, которые "еще не допилены"
2. не перепысывают из принципа "работает — не трогай"
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Тем, что существующие основаны на магии, а не на логике.
Т.е. сравнивать типы с типами это не логично и вообще какая-то магия. А вот сравнивать типы по их строковому представлению это куда как логичнее логичнее и прямее?
Здравствуйте, 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?"..
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Вот будь вместо шаблонов приличный макропроцессор, в котором можно и параметры вызова разобрать, и циклические конструкции использовать, и за счет объединения с компилятором использовать в условиях типы, классы и их свойства — какие у шаблонов остались бы преимущества?
Я не очень понимаю, что делает в профльном форуме эта околонаучная фантастика? Как можно всерьез обсуждать то, чего нет?