LINUX.ORG.RU

Возможности метапрограммирования в С++

 , , ,


0

3

Как в плюсах обстоят дела с метапрограммированием? Например такая задача: есть библиотека длинной арифметики, GMP называется. Даже есть привязка для С++ с перегруженными + - * / и прочими штуками. См https://gmplib.org/manual/C_002b_002b-Interface-General.html#C_002b_002b-Inte...
Так вот, допустим что надо сделать нечто, что делало бы оптимизацию операций с этими вот числами. Пример:

  if (a == 0) error();
  else return (a+a+a+a)/a;
Надо чтобы этот код был преобразован к виду
  if (a == 0) error();
  else return 4;
А например какой-нибудь код
 return a*c+b*c;
становился
 return c*(a+b);
и так далее.
Так вот. Чтобы решать такого рода задачи, придумали https://en.wikipedia.org/wiki/Expression_templates
Однако, код разбора и преобразования выражений в более оптимальный вид получается неуниверсальным - он работает только в компилтайме. Если я захочу в своей программе читать из stdin-а некую формулу, и эту формулу определенным образом преобразовывать, чтобы ее было легче считать, то эти expression templates оказываются совершенно бесполезными(можно разве что попробовать как-нибудь встроить непосредственно в программу кусок компилятора, который ответственен за разбор шаблонов, но это не является приемлемым решением). Так вот, можно ли как-нибудь сделать это универсально, чтобы и на этапе компиляции, и при выполнении я мог использовать ОДИН КОД для арифметических преобразований?
Единственный выход, который я вижу - метапрограммирование через кодогенерацию.

Эх, если был бы какой-нибудь язык программирования без GC, такой же низкоуровневый и быстрый как Си, и с гомоиконностью, чтоб можно было работать с неким абстрактным представлением кода вместо генерации синтаксически правильного Си/С++ кода...

★★
Ответ на: комментарий от monk

А если работать не с AST, а с текстом, так тебе и сейчас никто не мешает написать программу на C++, которая будет преобразовывать текст программы нужным образом и вызывать компилятор. Например, как сделано в Qt.

monk ★★★★★ ()

Немного поискав в интернете, наткнулся на библиотеку InteLib для плюсов, которую писал Столяров, и которая в этих самых плюсах реализует лисп-подобный синтаксис. http://www.intelib.org/
Я даже заглянул в гостевую книгу и нашел такую вот цитату http://stolyarov.info/comment/reply/44/895

Если из описания C++ выкинуть любые упоминания его треклятой стандартной библиотеки (как это сделал я), то останутся, во-первых, классы с механизмом защиты; во-вторых, конструкторы и деструкторы, в том числе их автоматический вызов в определённых ситуациях (кроме автоматического вызова деструктора при исчезновении объекта тут следует отметить ещё конструкторы копирования и преобразования); перегрузка символов операций для пользовательских типов, что, собственно, даёт на выходе абстрактные типы данных в полный рост. Что с помощью всего этого можно сделать? Ну, например, вот это: http://www.intelib.org ; а точнее — можно сделать что угодно, практически любые инструменты из других языков программирования поддаются моделированию таким способом. А язык при этом сам по себе низкоуровневый (ну, был когда-то, пока исключения в него не впендюрили), то есть у него отсутствуют (отсутствовали) ограничения, не позволяющие где попало использовать ту же джаву, C# и прочее.

Итого: C++ мог (когда-то давно) стать универсальным языком, то есть таким, перед которым ни у каких других языков нет осязаемых преимуществ вне зависимости от решаемой задачи. Разумеется, этот момент упущен, сейчас C++ (даже без STL) — просто язык высокого уровня, притом кривой, а с учётом последних «стандартов» — попросту нежизнеспособный.

Так вот, у меня вопрос. Позволяет ли данная библиотека решить поставленную мной задачу? Croco
Просто у меня создается ощущение, что С++ не может в принципе стать универсальным языком ввиду его негомоиконности. Т.е. надо попросту выкинуть на помойку этот с++ синтаксис заменив его на лисп, оставив при этом плюсовую семантику

SZT ★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Просто у меня создается ощущение, что С++ не может в принципе стать универсальным языком ввиду его негомоиконности. Т.е. надо попросту выкинуть на помойку этот с++ синтаксис заменив его на лисп, оставив при этом плюсовую семантику

Ну представим, что мы это сделали. И что дальше? Чтобы ты мог «использовать один код» придётся ращить с собой компилятор в рантам, как это лисп и делает. В итоге куча народу начнёт ныть, что «потерянна универсальность» так как рантайм стал намного жирнее. Этот Столяров панику из-за исключений разводит, которые отключаются, пусть и нестандартно. А уж чем ему стандартная библиотека не угодила я вообще не понимаю.

Плюс ещё такой момент - куча народу просто не увидит преимуществ в гомоиконности и тоже будет ныть, что язык испортили. В общем, теряем значительную часть старой аудитории и приобретаем что? Несколько лисперов начнут его использовать? Причём далеко не все, так как у них, как и у всех, есть свои привычки, предубеждения и т.д.

DarkEld3r ★★★★ ()
Последнее исправление: DarkEld3r (всего исправлений: 1)
Ответ на: комментарий от DarkEld3r

Чтобы ты мог «использовать один код» придётся ращить с собой компилятор в рантам

Необязательно. Если не встраивать eval в рантайм, этого делать не надо.

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

Язык и так уже порядочно испортили всяким ненужным хламом, так что лишняя гомоиконность не помешает

SZT ★★ ()
Ответ на: комментарий от SZT

Если не встраивать eval в рантайм, этого делать не надо.

Как тогда будет работать «чтение произвольной формулы из stdin» и т.д.?

Язык и так уже порядочно испортили всяким ненужным хламом

Сложилось впечатление, что на С++ ты (активно) не пишешь. Ошибаюсь? В любом случае, было бы интересно послушать, что на твой взгляд является «ненужным хламом, который портит язык».

Тут, кстати, тоже забавный момент - (практически?) у любой фичи найдутся как защитники так и те, кто будет кричать «не нужно». Вывод сделать сможешь?

DarkEld3r ★★★★ ()
Ответ на: комментарий от DarkEld3r

Как тогда будет работать «чтение произвольной формулы из stdin» и т.д.?

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

Сложилось впечатление, что на С++ ты (активно) не пишешь. Ошибаюсь? В любом случае, было бы интересно послушать, что на твой взгляд является «ненужным хламом, который портит язык».

Ну очевидно, что если я задаю подобные вопросы, я на нем активно не пишу. Если б я на нем писал, я бы уже очевидно знал, что подобные вещи в плюсах не решаются никаким способом, кроме как написанием кода на плюсах, делающим код на плюсах.
А ненужный хлам это например эти дурацкие constexpr-ы, которые МОГЛИ БЫ БЫТЬ пригодны для решения поставленной задачи, если бы ими можно было генерировать код, который бы на этапе компиляции ВСТАВЛЯЛСЯ бы внутрь исходника, черт возьми! А еще лучше, чтобы у меня была возможность делать код, выполняющийся на этапе компиляции, но при этом без требования функциональной чистоты. Например вот такой код
https://ideone.com/RHz5vW - плюсошаблоны и кодогенерация на С++
mixin-ы из D http://melpon.org/wandbox/permlink/22k35NmuFvFuVGKu

В D мне в случае кодогенерации не надо заморачиваться с выплевыванием исходника в stdin и последующей компиляции из него

Или например SFINAE и этот их std::enable_if. Почему б не сделать нормальный способ работы с типами, вместо этих костылей?

Или например подход с метапрограммированием на плюсошаблонах (не просто там генерация шаблонных функций, а именно попытки метапрограммирования на этом). Код на шаблонах, если он например предназначен для упрощения арифметических выражений (как в задаче из ОП-поста) оказывается непригодным для использования на этапе выполнения, и по факту его надо полностью будет заново написать с нуля для рантайма. А лучше этот код на шаблонах вообще не писать, а просто сделать только лишь вариан для рантайма, кодогенерировать им упрощенные формулы и включать их при компиляции

SZT ★★ ()
Последнее исправление: SZT (всего исправлений: 2)

Если я захочу в своей программе читать из stdin-а некую формулу, и эту формулу определенным образом преобразовывать, чтобы ее было легче считать

Т.е. ты хочешь свой по сути ЯП и свой компилятор со своими оптимизациями к нему, но ищешь простых путей, надеясь, что существует волшебный язык, который все сделает за тебя? Да еще и без трансляции и кодогенерации? Чудес не бывает, если тебе надо рабочее решение - бери libclang, пиши руками оптимизации, генерируй код и получай максимально быстрый код. Если хочешь продолжать ныть - что ж, дело твое.

anonymous ()
Ответ на: комментарий от SZT

А ненужный хлам это например эти дурацкие constexpr-ы,

Из того, что инструмент недостаточно мощный не следует его бесполезность. Ну и изначально ты говорил не просто о «ненужных фичах», а о вещах которые «испортили язык». Разве constexpr что-то испортили? Местами ведь стало удобнее. Может и недостаточно хорошо, но явно не хуже.

Если D устраивает, то почему его не используешь? Ну и с каких пор там есть гомоиконность?

DarkEld3r ★★★★ ()
Ответ на: комментарий от DarkEld3r

Из того, что инструмент недостаточно мощный не следует его бесполезность.

Ну как сказать. Эти constexpr-ы например поощряют(приучают) писать код в особом стиле, когда мы не через указатели меняем некие данные, а через return-ы нечто возвращаем. Рассмотрим что-нибудь простенькое, например сортировку пузырьком http://rosettacode.org/wiki/Sorting_algorithms/Bubble_sort#C и попробуем ее переделать на эти constexpr. Получится что-то вроде http://ideone.com/Kythll
Пришлось изменить сигнатуру функции и возвращать сотрированный массив через return. В constexpr можно засовывать только лишь чистые функции без побочных эффектов, а это значит что если я захочу взять некий готовый код и адаптировать его в эти constexpr, (а в коде этом будут всевозможные memcpy, malloc, и допустим он принимает указатели на массив из char, что-то в этот массив пишет и проч.) мне надо будет очень сильно его переделывать(возможно даже переписать с нуля). Если же я буду писать некий код с нуля, с прицелом на то, чтобы я этот код мог использовать в constexpr, мне придется придерживаться этих дурацких правил, что может пойти в ущерб читабельности и производительности кода. Так что эти constexpr можно даже назвать вредными, т.к. они приучают писать код в этом недофункциональном стиле.

Если D устраивает, то почему его не используешь? Ну и с каких пор там есть гомоиконность?

Потому что немейнстрим. Будет относительно трудно найти людей, которые будут готовы пилить код в этом D. В нем нет гомоиконности, но это явно лучше, чем то, что есть в С++

SZT ★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Эти constexpr-ы например поощряют(приучают) писать код в особом стиле

Ага. А теперь зайдём с другой стороны: что приходилось делать до constexpr? Писать на шаблонах с теми же ограничениями, только в ещё более «особом стиле» и ещё с большим ущербом читабельности. Возможность переписать любой код через constexpr никто и не обещал.

Насчёт производительности не понял. Можно пример? Всё-таки constexpr предполагается использовать для вычислений во время компиляции.

Потому что немейнстрим. Будет относительно трудно найти людей, которые будут готовы пилить код в этом D.

Дык, если изобрести «правильный С++ с гомоиконностью», то он тоже мейнстримом не станет. А дальше тебе надо определиться - даёт ли D достаточные преимущества. Если да, то людей можно и обучить, если у тебя есть ресурсы. Опять же, способствовать его популярности будешь. Для начала можно исходную задачу решить и показать всем как надо.

DarkEld3r ★★★★ ()
Ответ на: комментарий от DarkEld3r

Насчёт производительности не понял. Можно пример? Всё-таки constexpr предполагается использовать для вычислений во время компиляции.

А попробуй в ту самую сортировку пузырьком на constexpr-ах вписать очень большой массив и скомпилировать это. Потом сравни с временем работы того же кода в ратнайме с таким же точно массивом, только без constexpr.
Этот constexpr-код сортировки в компилтайме отрабатывает очень долго по сравнению с тем, как если эту сортировку скомпилировать обычным образом и передать ей на вход массив, который надо отсортировать. При сортировке больших массивов он отрабатывает так долго, что clang начитает предполагать что там бесконечный цикл, и прекращает сортировку компиляцию, а gcc падает с internal compiler error. Кроме того, я почти уверен что если использовать в рантайме код, написанный в подобном недофункцильнальном стиле, он окажется в общем случае медленней, чем код, написанный в обычном стиле

SZT ★★ ()
Ответ на: комментарий от SZT

А попробуй в ту самую сортировку пузырьком на constexpr-ах вписать очень большой массив и скомпилировать это.

Давай не будем мешать в кучу время компиляции и время выполнения.

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

И?

DarkEld3r ★★★★ ()
Ответ на: комментарий от DarkEld3r

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

И?

Это значит что если я например буду писать некий код таким образом, чтобы его использовать и в constexpr-ах и в обычном рантайме, мне придется писать код таким вот неэффективным образом, и в рантайме он у меня будет работать медленней, чем если бы я на эти constexpr-ы просто забил, и писал по-нормальному только лишь для рантайма.

SZT ★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Это значит...

Это очевидно. Честно говоря, твоя претензия выглядит примерно как «если я захочу использовать один код и для ООП и для процедурного программирования, то у меня не получится». Ну да, не получится. И что? Прост constexpr решают определённую задачу. Пихать их во весь код «просто потому что можно» нет никакого смысла. Можно ещё пожаловаться на то, что статический и динамический полиморфизм в языке разными средствами реализовывается.

На всякий случай, я не хочу сказать, что в языке всё идеально сделано. Просто вот конкретно эта претензия странная.

Ну и мне по прежнему интересно какие новые фичи именно «ухудшают язык». constexpr - не катит. Без них лучше не было бы.

DarkEld3r ★★★★ ()
Ответ на: комментарий от DarkEld3r

Ну и мне по прежнему интересно какие новые фичи именно «ухудшают язык». constexpr - не катит. Без них лучше не было бы.

С одной стороны можно сказать «Ну и что, что добавили этот constexpr. Я вижу что он ограничен по сравнению с кодогенерацией, и просто не буду его использовать в своих программах». А с другой стороны, кто-то может увидеть эти constexpr и начать его активно использовать, и его код будет из-за этого по пол дня компилироваться, и в рантаме все будет тормозить, и вообще... Иными словами, факт наличия этой недофичи порождает код, в котором эта фича используется, однако эта фича объективно ХУЖЕ чем кодогенерация, и поэтому лучше чтоб ее вообще не было, чтобы всякие ***** ее не использовали и не порождали говнокода с ней. Или надо при описании этой фичи писать жирными буквами, что constexpr объективно хуже кодогенерации. Существующие на данный момент компиляторы на этапе компиляции интерпретируют этот constexpr значительно медленней, чем если бы этот код был скомпилирован нормальным способом и просто запущен на исполнение для кодогенерации. Код на constexpr должен писаться с рядом ограничений ...тут_про_то_что_нужна_функциональная_чистота_и_надо_возвращать_через_return... так что советуем для чего-то сложного не использовать эту недофичу, а делать кодогенерацию.

SZT ★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

Иными словами, факт наличия этой недофичи порождает код, в котором эта фича используется, однако эта фича объективно ХУЖЕ чем кодогенерация, и поэтому лучше чтоб ее вообще не было, чтобы всякие ***** ее не использовали и не порождали говнокода с ней.

Иными словами, сушка волос в микроволновке оказывает негативное влияние на здоровье и такое использование микроволновок объективно ХУЖЕ, чем использование фена, поэтому лучше, чтобы микроволновок вообще не было, чтобы всякие ***** не засовывали туда свои головы.

Простите мне мой французский, но такое впечатление, что вы попытались засунуть constexpr куда не следует, отгребли проблем и теперь наезжаете на полезную фичу из-за собственной глупости.

eao197 ★★★★ ()
Ответ на: комментарий от eao197

Простите мне мой французский, но такое впечатление, что вы попытались засунуть constexpr куда не следует, отгребли проблем и теперь наезжаете на полезную фичу из-за собственной глупости.

А куда их собственно надо засовывать? Какого рода задачи можно ими решать, которые бы не решались кодогенерацией? Или может эти constexpr позволяют решать задачи лучше, чем кодогенерация?

SZT ★★ ()
Ответ на: комментарий от SZT

А про какую кодогенерацию вы говорите? В C++ нужно нехило приседать, чтобы получить кодогенерацию в run-time. Либо же нужно чем-то генерировать C++ный код в pre-compile-time, т.е. использовать какой-то DSL из которого какой-то инструмент генерирует C++ (например, как protobuf генерирует классы из proto-файлов). Естественно, constexpr не решает таких задач. А вот построить в compile-time какую-нибудь константу, которую затем компилятор будет подставлять в код... Почему бы и нет?

eao197 ★★★★ ()
Ответ на: комментарий от eao197

О кодогенерации в run-time речи не идет. Для нормальной кодогенерации в run-time надо делать JIT, а это уже выходит за рамки плюсов и их стандарта. Речь идет о том, чтобы использовать некий код и на этапе комиляции, и непосредственно при выполнении. Например, упрощать арифметические выражения с bigint-ами. constexpr не позволяют эффективно решать данную задачу т.к. накладывают ряд существенных ограничений... Об этом всем я уже писал, не вижу смысла повторяться. Там я и сортировку пузырьком на constexpr показывал. Перечитайте нить.

Если же constexpr задумывался лишь как удобный способ просчитать константы на этапе компиляции, то это просто смешно... Усилия, затраченные на реализацию этого constexpr во всех актуальных C++ компиляторах, просто несоизмеримы с полезностью данной фичи, если ее предполагается использовать только лишь для констант.

SZT ★★ ()
Ответ на: комментарий от SZT

Для нормальной кодогенерации в run-time надо делать JIT, а это уже выходит за рамки плюсов и их стандарта.

За рамки стандарта плюсов выходит вообще практически все: файловая система, сеть, IPC, GUI, криптография и еще куча вещей, необходимых для чего-либо более сложного, чем HelloWorld. Тем не менее, люди для плюсов уже давным давно делали run-time кодогенерацию, например, путем использования C++компилятора: генерился C++ный код, пропускался через компилятор и линкер, на выходе получалась, скажем, DLL, которая подгружалась и из которой дергался нужная экспортированная функция. Или же на выходе получался новый исполнимый файл, запускавшийся дочерним процессом и общение с которым происходило через IPC.

Например, упрощать арифметические выражения с bigint-ами. constexpr не позволяют эффективно решать данную задач

Ну так чего вы до них докопались? Кто вам вообще обещал, что constexpr облегчит вам метапрограммирование на C++?

Если же constexpr задумывался лишь как удобный способ просчитать константы на этапе компиляции, то это просто смешно...

Кому смешно, а кто-то пользуется. Например, с помощью constexpr можно реализовать функцию, возвращающую размерность вспомогательного массива, нужного для решения какой-то задачи. Скажем, что-то вроде:

float tmp_array[ calc_temp_array_size(12, 15, 100500) ];
Если calc_temp_array_size() — это constexpr-функция, то мы получаем возможность размещать tmp_array на стеке или в статической памяти. В отсутствие constexpr вы что предлагаете делать? Поржать и оформить calc_temp_array_size макросом?

Усилия, затраченные на реализацию этого constexpr во всех актуальных C++ компиляторах, просто несоизмеримы с полезностью данной фичи, если ее предполагается использовать только лишь для констант.

Откуда дровишки? Участвовали в разработке GCC, Clang, Intel C++ или Microsoft С++?

eao197 ★★★★ ()
Ответ на: комментарий от eao197

Если calc_temp_array_size() — это constexpr-функция, то мы получаем возможность размещать tmp_array на стеке или в статической памяти. В отсутствие constexpr вы что предлагаете делать?

Предлагаю сделать код, который

printf("%" PRIu64 "\n", calc_temp_array_size(12, 15, 100500) );
Потом
./a.out > arrsz.h
float tmp_array[ 
                 #include "arrsz.h"
               ];
При желании это все можно автоматизировать каким-нибудь препроцессором, чтобы можно было делать
float tmp_array[ 
                 /*## EXEC(printf("%" PRIu64 "\n", calc_temp_array_size(12, 15, 100500) ); */
               ];

Откуда дровишки? Участвовали в разработке GCC, Clang, Intel C++ или Microsoft С++?

А вы прикиньте, что надо сделать в том же GCC чтобы обеспечить возможность обрабатывать эти constexpr-ы в компилтайме, учитывая еще тот факт, что это может быть кросскомпилятор, который скажем на интеле работает, а код генетирует под какой-нибудь AVR 16-битный. А сделать надо ИНТЕРПРЕТАТОР этого C++

SZT ★★ ()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от SZT

А вы прикиньте, что надо сделать в том же GCC чтобы обеспечить возможность обрабатывать эти constexpr-ы в компилтайме

А ты прикинь, gcc и так это умел в рамках оптимизаций. constexpr по факту больше нужен программисту, чтоб объяснять ему, почему его код не будет соптимизирован на этапе компиляции.

учитывая еще тот факт, что это может быть кросскомпилятор, который скажем на интеле работает, а код генетирует под какой-нибудь AVR 16-битный. А сделать надо ИНТЕРПРЕТАТОР этого C++

Ты упорот, кросскомпиляция тут вообще никаким боком не влияет.

anonymous ()
Ответ на: комментарий от SZT

Предлагаю сделать код, который...Потом...При желании это все можно автоматизировать каким-нибудь препроцессором, чтобы можно было делать

Вот для того, чтобы через 30 лет после появления C++ на свет не приходилось все это делать и дружить всю эту pre-compile-time байду с разными системами сборки, IDE, статическими анализаторами и прочим инструментарием, и сделали в языке поддержку constexpr — один раз в коде написал и никаких заморочек.

А вы прикиньте, что надо сделать в том же GCC чтобы обеспечить возможность обрабатывать эти constexpr-ы в компилтайме

Проблемы негров шерифа, вообще-то, не волнуют. Мне как-то фиолетово, сколько сил вложили разработчики GCC в поддержку constexpr. Раз такую фичу через комитет продавили, значит она изначально выглядела реализуемой. И то, что со временем компиляторы становятся более сложными и поддерживают все более и более навороченные языковые конструкции — это нормально, т.к. прогресс не стоит на месте и всякое такое...

eao197 ★★★★ ()
Ответ на: комментарий от SZT

Нет. Компилятор в рамках оптимизации без constexpr тебе не будет сортировку пузырьком считать

Потому-что там, очевидно, есть ограничения на глубину вычислений, чтоб компилятор на оптимизациях не подвисал на неопределенное время. А с constexpr он просчитывает все без ограничений - так пользователь попросил. Вообще еще в 2001-м году gcc умел сворачивать вычисления с if/goto/...:

https://gcc.gnu.org/news/ssa-ccp.html

anonymous ()

ИМХО, ты маешься дурью: возьми да получи аст, оптимизируй его и транслируй во что тебе там надо, раз ты такой хардкорный плюсовик. Если же вдруг окажется, что не утюг формулы интерпретировать будет, юзай лишп или хаскель, уж не знаю где меньше *ботни получится.

anonymous ()
Ответ на: комментарий от SZT

И я хочу, чтобы у меня был код по упрощению алгебраических выражений, который может быть применен и для компилтайма, и для рантайма. Плюсы тут притом, что в них это нельзя нормально разрулить, или дублирование кода, или кодогенерация

Думается мне, что тут можно заюзать ленивые вычисления — подойдет и для рантайма и для компилтайма (но, конечно, будет медленее в рантайме чем шаблоны). Например:

  1. Дано выражение в коде (или прочитано с stdin):
    a*b + a*c
    
  2. Добавляем в класс BigInt «аккумулирующие» операторы:
    class BigInt {
    public:
        BigInt operator + (const BigInt &other) const {      
            // конструируем новый BigIntPrivate --
            // дополняем дерево новой операцией: "+ other"
    
            // можем провести оптимизацию: 
            // в случае a*b + a*c детектим одинаковый операнд
            // и "вращаем" дерево выражения соответственно
            
            return BigInt(newBigIntPrivate);
        } 
    
        // другие операторы аналогично
    
        BigInt& compile() {
           // разбираем дерево
           // оптимизируем (если не сделали этого раньше)
           // считаем (на этот раз работаем уже только с BigIntPrivate)
           // помещаем новое значение в BigIntPrivate
           return *this;
        }
    private:
        // Отдельно сохраняем данные BigInt:
        // 1. Дерево операций (или обратную польскую нотацию)
        // 2. Собственно само число (данные)
        // Позже используем для Copy-on-Write
        BigIntPrivate d; 
    };
    
  3. Используем одни и те же методы BigInt в компайлтайме и рантайме.
KennyMinigun ★★★★★ ()
Ответ на: комментарий от KennyMinigun

Дано выражение в коде (или прочитано с stdin):

или прочитано с stdin

Если оно прочитано со stdin, то... что дальше? Парсим выражение руками и генерируем AST снова же руками?

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Парсим выражение руками и генерируем AST снова же руками?

И правда, проблема.

Почему-то подумал, что тут выйдет просто добавлять операции в дерево последовательно.

KennyMinigun ★★★★★ ()
Ответ на: комментарий от MKuznetsov

за давностью лет не скажу за float vs double, но внутри функций типа f(x,y) приходилось делать разные ветки в зависимости от абсолютных и относительных величин x,y - исключительно с целями борьбы с погрешностями.

так что если программер сказал x=a*c+b*c то компилер и обязан вычислять именно в такой последовательности.

Поковырялся тут в кишках компилятора GCC. https://gcc.gnu.org/viewcvs/gcc/trunk/gcc/simplify-rtx.c?view=markup&path... Вот такая штука там есть, которая как раз таки может переиначивать порядок операций с плавучкой. Похоже что за это отвечает опция -funsafe-math-optimizations описанная тут https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

Вообще я вот глядя на весь этот код GCC как-то с трудом представляю, как в этом всем можно разобраться. Возникает желание все это нафиг переписать, и вообще втулить какую-то нормальную систему символьных вычислений вместо этого непоймичего

SZT ★★ ()