что такое constexpr c

constexpr (C++)

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

Для ограничения сложности const вычислений Ant времени компиляции и их возможного влияния на время компиляции стандарт c++ 14 требует, чтобы типы в const выражениях Ant были литеральными типами.

Синтаксис

** constexpr **тип литерала Ident if Иер = const Ant-Expression ;
** constexpr **тип литерала Ident if Иер <const Ant-Expression > ;
** constexpr **тип литерала Ident if Иер ( params ) ;
** constexpr **ctor ( params ) ;

Параметры

params
Один или несколько параметров, каждый из которых должен быть типом литерала и сам должен быть const выражением Ant.

Возвращаемое значение

constexpr Переменная или функция должна возвращать литеральный тип.

Переменные constexpr

Ссылка может быть объявлена как constexpr при выполнении обоих этих условий: объект, на который указывает ссылка, инициализируется const выражением Ant, а любые неявные преобразования, вызванные во время инициализации, также const Ant выражениями.

Все объявления constexpr переменной или функции должны иметь constexpr спецификацию if Иер.

Функции constexpr

constexpr Функция должна принимать и возвращать только типы литералов.

constexpr Функция может быть рекурсивной.

Он не может быть виртуальным. constРуктор не может быть определен, как constexpr Если включающий класс имеет какие-либо виртуальные базовые классы.

Текст не может содержать goto операторы или try блоки.

Явная специализация не constexpr шаблона может быть объявлена следующим образом constexpr :

Явная специализация constexpr шаблона также не должна быть такой constexpr :

к constexpr функциям в Visual Studio 2017 и более поздних версий применяются следующие правила.

Он может содержать объявления локальных переменных, но переменная должна быть инициализирована. Он должен быть типом литерала и не может быть static или локальным потоком. Локально объявленная переменная не обязательно должна быть const и может изменяться.

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

Название constexpr

Параметр компилятора /Zc: externConstexpr заставляет компилятор применить внешнюю компоновку к переменным, объявленным с помощью constexpr модификатора extern. в более ранних версиях Visual Studio либо по умолчанию, либо при использовании параметра /zc: externConstexpr- spec if иед, Visual Studio применяет внутреннюю компоновку к constexpr переменным, даже если extern используется ключевое слово. параметр /zc: externConstexpr доступен начиная с обновления Visual Studio 2017 15,6 и по умолчанию отключен. Параметр /permissive- не включает /Zc: externConstexpr.

Пример

Требования

Visual Studio 2015 или более поздней версии.

Источник

Упрощение кода с помощью if constexpr в C++17

Несколько новых возможностей C++17 позволяют написать более компактный и ясный код. Это особенно важно при шаблонном мета-программировании, результат которого часто выглядит жутко…

Введение

Статический if в форме if constexpr полезная возможность, появившаяся в C++17. Недавно на сайте Meeting C++ была опубликована статься о том, как автор статьи Jens упростил код, используя if constexpr : Как if constexpr упрощает ваш код в C++17.

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

Для чего нужен if во время компиляции?

Услышав об этом в первый раз, возможно вы спросите, зачем нужен статический if и эти сложные шаблонные выражения… Разве нормальный if не будет работать?

Мы получим что-то похожее на это:

In instantiation of ‘std::__cxx11::string str(T) [with T = std::__cxx11::basic_string ; std::__cxx11::string = std::__cxx11::basic_string ]’: required from here error: no matching function for call to ‘to_string(std::__cxx11::basic_string &)’ return std::to_string(t);

is_same даёт true для используемого типа (string), и мы можем просто вернуть t без преобразований… но что пошло не так?

std::enable_if

Один из способов написать статический if в C++11/14 — использовать enable_if (и enable_if_v начиная с C++14). Он имеет достаточно странный синтаксис::

enable_if выводит тип T, если условие B истинно. Иначе, согласно SFINAE, частичная перегрузка функции удаляется из доступных перегрузок фунции.

Мы можем переписать наш простой пример так:

Это не просто, не так ли?

Использование первое — сравнение чисел

Я нашёл этот пример в Практическая головоломка современного C++ (Practical Modern C++ Teaser) — фантастическое введение в возможности современного C++ от Patrice Roy. Он любезно разрешил мне включить его пример.

А сейчас посмотрим, как это делается в C++17:

if constexpr вычисляется во время компиляции и затем пропускается код одной из ветвей выражения.

Здесь используются чуть больше возможностей C++17. Вы видите, какие?

Использование второе — фабрика с переменным количеством параметров

В главе 18 книги «Эффективное использование С++» Скотта Майрса описывается метод, названный makeInvestment :

Для примера, ниже предлагаются типы наследников:

Пример из книги слишком идеализированный и не рабочий — он работает, пока конструкторы ваших классов принимают одинаковое число и одинаковые типы входных аргументов.
Скотт Майрес комментирует в исправлениях и дополнениях к его книге «Эффективное использование С++» так:

Интерфейс makeInvestment не практичный, потому что предполагается, что наследники могут быть созданы из одних и тех же наборов аргументов. Это особенно заметно в реализации выбора конструируемого объекта, где аргументы передаются в конструкторы всех классов с помощью механизма perfect-forwarding (идеальная передача).

Для примера, если у вас есть два класса, конструктор одного принимает два аргумента, а другого — три, то такой код не будет компилироваться:

Вот код, который мог бы работать:

До C++17

В этом случае мы использовали бы std::enable_if так:

std::is_constructible позволяет быстро проверить, будет ли данный тип конструироваться из заданного списка аргументов. // @cppreference.com

В C++17 немного проще, появился новый помощник:

Так что мы можем сделать код немного короче… Однако, использование enable_if всё ещё ужасно и сложно. Как насчёт C++17?

С if constexpr

Мы можем даже расширить функциональность логироваием действий, используя свёртку выражения:

Весь сложный синтаксис выражений с enable_if ушёл прочь; нам даже не нужна перегрузка функции. Мы можем написать выразительный код всего лишь в одной функции.

Заключение

Условные выражения времени компиляции — замечательная возможность, которая сильно упрощает использование шаблонов. Кроме того, код становится яснее, чем при использовании существовавших ранее решений: статической диспетчеризации (tag dispatching) или enable_if (SFINAE). Сейчас вы можете выразить свои намерения «похоже» на код в рантайме.

В этой статье рассматривались только простые выражения, и я призываю вас исследовать более широко применимость новых возможностей.

Возвращаясь назад к нашему примеру функции str : можете ли вы сейчас переписать её используя if constexpr?

Источник

Спецификатор constexpr в C++11 и в C++14

И ответ в виде дроби будет получен на этапе компиляции:
Answer is 37/24
Сразу предупреждаю, код этой библиотеки сложно понять.
Кому эта тема интересна, добро пожаловать под кат!

Что такое constexpr?

constexpr-функция

constexpr-переменная

constexpr тип = expression;
Ключевое слово в данном случае означает создание константы. Причем expression должно быть известно на этапе компиляции.

Рассмотрим такой пример:

Ограничения

Теперь, когда вы поняли, как это все удобно, можно добавить ложку дегтя в бочку меда. Причем довольно большую ложку.

В случае вызова функции во время компиляции мы увидим ошибку, что конструкция throw не может находиться в constexpr-функции, а в runtime функция выбросит исключение.
Ошибку сложно будет найти, но хоть что-то.

В итоге сложно писать, сложно отлаживать, сложно понимать такие конструкции.
Но все не так плохо, в C++14 очень многие ограничения уберут.

Изменения в C++14

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

Второе незначительное изменение заключается в том, что теперь constexpr функции-члены класса не являются константными.
В C++11 следующие строчки были равносильными, а в С++14 это уже не так:

Объяснение этому можно найти тут.

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

Пример использования constexpr на C++11

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

Итак, мы хотим, чтобы можно было писать такой код:

Объявляется пользовательский литерал таким образом:

В качестве ассерта будет использоваться следующий макрос:

Библиотека может складывать, вычитать, умножать, делить, возводить в степень, также есть поддержка скобок. Реализовано это будет с помощью рекурсивного спуска.

Для считывания числа будут 3 функции (одна основная и две вспомогательных):

Работа со скобками:

Дальше идет функция возведения в степень:

Произведение и деление обрабатываются в одной функции:

Аналогично происходит с суммой и разностью:

И наконец, осталось реализовать функцию solve :

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

Источник

Урок №37. const, constexpr и символьные константы

Обновл. 11 Сен 2021 |

До этого момента, все переменные, которые мы рассматривали, были обычными. Их значения можно было изменить в любое время, например:

Тем не менее, иногда полезно использовать переменные, значения которых изменить нельзя — константы.

Константы

Чтобы сделать переменную константой — используйте ключевое слово const перед типом переменной или после него. Например:

Несмотря на то, что язык C++ позволяет размещать const как перед типом данных, так и после него, хорошей практикой считается размещать const перед типом данных.

Константы должны быть инициализированы при объявлении. Изменить их значения с помощью операции присваивания нельзя:

Объявление константы без её инициализации также вызовет ошибку компиляции:

Обратите внимание, константы могут быть инициализированы и с помощью неконстантных значений:

Ключевое слово const является наиболее полезным (и наиболее часто используемым) с параметрами функций:

Время компиляции и время выполнения

Когда вы находитесь в процессе компиляции программы, то это время компиляции (англ. «compile time»). Компилятор проверяет вашу программу на синтаксические ошибки и, если их нет, конвертирует код в объектные файлы.

Временной промежуток с момента старта выполнения программы и до момента окончания её работы называется временем выполнения программы (англ. «runtime»). Код выполняется строка за строкой.

Спецификатор constexpr

В языке C++ есть два вида констант:

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

Константы времени компиляции. Их значения определяются во время компиляции программы. Например, переменная со значением силы тяжести на Земле является константой времени компиляции, так как мы её определяем во время написания программы (до начала её выполнения).

В большинстве случаев не важно какой тип константы вы используете: времени выполнения или времени компиляции. Однако, все же есть несколько ситуаций, когда C++ может потребовать константу времени компиляции вместо времени выполнения (например, при определении длины массива фиксированного размера — мы рассмотрим это несколько позже). Так как есть 2 типа констант, то компилятору нужно постоянно отслеживать, к какому из них относится какая переменная. Чтобы упростить это задание, в C++11 добавили спецификатор constexpr, который сообщает компилятору, что текущая переменная является константой времени компиляции:

Источник

Дизайн и эволюция constexpr в C++

что такое constexpr c. Смотреть фото что такое constexpr c. Смотреть картинку что такое constexpr c. Картинка про что такое constexpr c. Фото что такое constexpr c

У constexpr с каждым годом становится больше возможностей. Сейчас использовать в compile-time вычислениях можно почти всю стандартную библиотеку. Пример вычисления числа до 1000 с наибольшим количеством делителей: ссылка на код.

C++98 и C++03: Сословия среди const-переменных

В C++ в некоторых местах нужно использовать целочисленные константы, значения которых должны быть известны в compile-time. Стандарт разрешает записывать константы в виде несложных выражений, как в этом коде:

Эти выражения описаны в разделе [expr.const] и называются constant-expression. Они могут содержать только:

Литералы (туда входят целые числа, это интегральные типы)

В стандартах C++98/03 есть два вида static initialization:

zero-initialization, память заполняется нулями, затем в ходе программы изменяется

initialization with a constant expression, память (если нужна) сразу содержит вычисленное значение

[Note: Все остальные инициализации называются dynamic initialization, мы их не рассматриваем. — end note]

[Note: zero-initialized переменная во время работы программы в свою очередь может быть проинициализирована еще раз «нормальным» значением, это уже будет dynamic initialization (пусть даже до старта main ). — end note]

Рассмотрим пример с обоими видами переменных:

Если нигде не берется адрес constant-expression переменной, то скомпилированной программе разрешено не резервировать для нее память, поэтому «заставим» ее это сделать. Выведем значения переменных и их адреса:

Скомпилируем объектный файл и посмотрим на таблицу символов:

Таким образом, одни const-переменные «константнее» других. Насколько известно, в то время не было простого способа проверить или как-то проконтролировать, что переменная была initialized with a const. expr.

0-∞: Вычислитель констант в компиляторе

Чтобы представлять, как константые выражения вычисляются во время компиляции, нужно понимать устройство компилятора.

Компиляторы идейно похожи друг на друга, я опишу процесс вычисления на основе компилятора Clang/LLVM. Я скопировал базовую информацию про этот компилятор из своей прошлой статьи:

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

Количество стадий компиляций зависит от того, кто объясняет устройство компилятора. Анатомия компилятора многоуровнева и на самом абстрактном уровне выглядит так, что есть три разные программы:

Middle-end: LLVM IR оптимизируется в зависимости от настроек.

На менее абстрактном уровне находится фронтенд Clang, который выполняет такие действия (не рассматривая препроцессор и прочие «микро»-шаги):

Кодогенерация: создание LLVM IR по данному AST.

Итак, вычисление константных выражений (и близкородственных ему вещей, как инстанцирование шаблонов) происходит строго в фронтенде компилятора C++ (в нашем случае в Clang), а LLVM такими вещами не занимается.

«Микросервис», который занимается вычислением константных выражений (от самых простых в C++98 до сложных в C++23), назовем условно вычислитель констант.

Если согласно Стандарту в каком-то месте кода ожидается константное выражение; и выражение, которое там находится, действительно удовлетворяет требованиям на константное выражение, то Clang должен «не отходя от кассы» в 100% случаев уметь вычислять его.

Ограничения на константные выражения на протяжении лет постоянно смягчались, а вычислитель констант Clang соответсвенно постоянно усложнялся, вплоть до управления моделью памяти.

Исходник вычислителя констант находится в lib/AST/ExprConstant.cpp и на момент написания статьи разросся до почти 16 тысяч строк. С годами он научился интерпретировать много всего, например циклы (EvaluateLoopBody), и всё это на синтаксическом дереве.

Вычислитель констант используется не только для константных выражений, но также для поиска потенциальных багов в остальном коде. Это побочная выгода от технологии. Вот так находится переполнение для не-константного кода (могут максимум бросить warning):

2003: Макросы не нужны

Изменения в стандарт происходят через предложения.

Где находятся предложения и из чего они состоят?

Краткий обзор области со ссылками на разделы Стандарта;

Предлагаемое решение проблем;

Предлагаемые изменения в текст Стандарта;

Ссылки на предложения-предшественники и прошлые ревизии предложения;

По ссылкам на предыдущие предложения можно отследить эволюцию для каждого куска C++.

Далеко не все предложения из архива были в итоге приняты (хотя и могли быть использованы как база для других, принятых предложений), поэтому стоит понимать, что они описывают некий альтернативный тому времени вариант C++, а не кусок современного C++.

Предложение от 2003 года [N1521] Generalized Constant Expressions указывает на проблему того, что если часть выражения вычисляется с использованием вызова метода, то выражение не является constant-expression. Это заставляет злоупотреблять макросами, если нужно получить более-менее сложное константное выражение:

[Note: Забегая вперед, термин constant-valued не прижился что такое constexpr c. Смотреть фото что такое constexpr c. Смотреть картинку что такое constexpr c. Картинка про что такое constexpr c. Фото что такое constexpr cend note].

Таким образом, все переменные test1-5 из прошлого раздела становились бы «фундаментально» константными, без изменения в коде.

Предложение считает, что можно пойти еще дальше и надо рассмотреть вариант, что такой код тоже должен компилироваться:

Предложения обычно не идут далеко в дебри подробностей, как компиляторы могут его реализовать. В этом предложении пишут, что сложностей возникнуть не должно, и надо немного поправить constant folding, которые есть в большинстве компиляторов.

Как с переменными, программист не может проконтролировать, что метод является constant-valued.

2006-2007: Тайное становится явным

К счастью, через 3 года в следующих ревизиях этого предложения ([N2235]) признали, что слишком много неявности это плохо. В список проблем добавили невозможность контроля за инициализацией:

2007: Первые constexpr для структур данных

В этом году вышло предложение [N2349] Constant Expressions in the Standard Library, где пометили как constexpr некоторые методы и константы, а также некоторые методы контейнеров, например:

2008: Рекурсивные constexpr-методы

У компилятора существует некий предел вложенности вызовов (в clang это 512 вложенных вызовов), при превышении он откажется считать выражение.

2010: «const T&» как аргументы в constexpr-методах

Предложение [N3039] Constexpr functions with const reference parameters (a summary) разрешает константные ссылки в аргументах и как возвращаемое значение.

В общем случае работа со ссылками и указателями в constant-expression превращает C++-компилятор в C++-интерпретатор, поэтому накладываются различные ограничения.

Более-менее сложная работа со ссылками и попытки что-либо поломать не скомпилируются

2011: static_assert в constexpr-методах

2012: (Почти) любой код в constexpr-функциях

В 2012 году произошел большой рывок вперед с предложением [N3444] Relaxing syntactic constraints on constexpr functions. Есть множество простых методов, которых желательно уметь вычислять в compile-time, например степень что такое constexpr c. Смотреть фото что такое constexpr c. Смотреть картинку что такое constexpr c. Картинка про что такое constexpr c. Фото что такое constexpr c:

Так как в константных выражениях нельзя изменять переменные, циклы ( for / while / do /range-based for) заведомо невозможно использовать

switch и goto запрещены, чтобы вычислитель констант не моделировал сложные потоки управления

[Note: таких переменных не будет сильно много из-за жесткого ограничения на «глубину вызовов» что такое constexpr c. Смотреть фото что такое constexpr c. Смотреть картинку что такое constexpr c. Картинка про что такое constexpr c. Фото что такое constexpr cend note].

2013: (Почти) любой код в constexpr-функциях ver 2.0 Mutable Edition

Для реализации «constexpr for «-а рассматривалось четыре варианта.

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

Эти вычисления до сих пор происходят внутри своей «песочницы», ничто снаружи на них не влияет, поэтому, по идее, вычисление constexpr-выражения с одними и теми же аргументами будет давать один и тот же результат (не считая погрешностей в float- и double-вычислениях).

Для лучшего понимания я скопировал кусок кода из предложения:

От себя замечу, что теперь компилируется такой код:

2013: Легендарные const-методы и популярные constexpr-методы

Это стало актуальнее с мутабельностью в constexpr-вычислениях; но и до этого мешало использовать один и тот же метод в constexpr и не-constexpr коде:

Интересно, что предложение давало на выбор три опции, из них был выбран второй:

Статус-кво; минус: дублирование кода

constexpr не будет неявно значить const ; минус: ломает ABI ( const является частью mangled-имени метода)

Добавить новый квалификатор и писать constexpr A &getA() mutable < return a; >; минус: новый баззворд в конце объявления

2015-2016: Синтаксический сахар для шаблонов

В метапрограммировании шаблонов обычно перегружают методы, если в теле требуется разная обработка в зависимости от свойств типа. Пример страшного кода:

Предложение [N4461] Static if resurrected вводит выражение static_if (позаимствовав из языка D), чтобы код стал менее страшным:

И финальный вариант:

2015: Constexpr-лямбды

Чтобы понять, как возможно иметь constexpr-лямбды, нужно понимать, как они устроены «внутри». Есть статья про историю лямбд, где описано, как прото-лямбды существовали уже в C++03, и в сегодняшних лямбда-выражениях создается похожий класс, скрытый за чертогами компилятора.

Прото-лямбда для [](int x) < std::cout

2017-2019: Двойные стандарты

Затем оператор был заменен на «магическую» функцию std::is_constant_evaluated() ([P0595R2]) и в таком виде принят в Стандарт С++20.

Если предложение разрабатывается долго, то авторы иногда делают «rebase» (аналогично как в проектах в git/svn), приводя его в соответствие с обновившимся состоянием.

2017-2019: We need to go deeper

В constexpr-методах во время constexpr-вычислений пока нельзя использовать дебаггер и выводить логи. Предложение [P0596] std::constexpr_trace and std::constexpr_assert рассматривает введение специальных методов для этих целей.

2017: Злой двойник стандартной библиотеки

2017-2019: Constexpr обретает память

В презентации Constexpr ALL the thing! демонстрировался пример constexpr-библиотеки для работы с JSON-объектами (то же самое, но в бумажном виде, есть в [P0810] constexpr in practice):

Недоступна динамическая аллокация/деаллокация памяти.

Недоступен placement-new для вызова конструктора в аллоцированной памяти.

Вторая проблема. Работа с памятью не очень проста. Как уже упоминалось, вычислитель констант обязан отлавливать undefined behaviour в любом виде и останавливать компиляцию в случае его наличия.

Это значит, что вместе с многими объектами нужно трекать их «метаданные», которые держат руку на пульсе и не дают сломать выполнение программы. Пара примеров таких метаданных:

Жесткая связь между указателем или ссылкой и соответствующим ему реальным ранее созданным объектом (примеры undefined behavior: бесконечное множество)

Из-за этого не имеет смысла использовать подобные методы:

Простые new- и delete-выражения: int* i = new int(42);

Использование стандартного аллокатора: std::allocator (его подпилили напильником)

То есть его нельзя использовать из-за приведения к void* и placement-new (которые в общем виде в constexpr запрещены). А в предложении преобразовался в

Такой новый тип аллокации памяти назван transient constexpr allocations. Слово transient приблизительно можно перевести как «мимолетный» или «недолговечный».

В остальном, это предложение было принято.

2018: Поймай меня, если сможешь

2018: Я сказал constexpr!

Предложение [P1073] constexpr! functions вводит новое ключевое слово constexpr! для методов, которые должны работать только в compile-time. Эти методы называются immediate-методами.

2018: Слишком радикальный constexpr

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

— метод помечается как constexpr, если возможно.

2020: Долговечная constexpr-память

Другими словами, вот что должен делать вычислитель контант:

Имитировать вызов деструктора у данного объекта (не вызывая его на самом деле), и проверить что этот вызов освободил бы всю non-transient память.

Если все проверки прошли успешно, то консистентность доказана. Non-transient allocations можно двигать в static storage.

Это звучит логично, и допустим, что это всё реализовано. Но тогда получим проблему с подобным кодом с non-transient памятью, которую стандарт не будет запрещать менять, и тогда проверка на вызов деструктора будет бессмысленной:

[Note: В реальности такой код получил бы отпор от ОС за попытку записи в read-only сегмент RAM, но это физическая константность. А в коде должна быть логическая константность. что такое constexpr c. Смотреть фото что такое constexpr c. Смотреть картинку что такое constexpr c. Картинка про что такое constexpr c. Фото что такое constexpr cend note]

У указательных типов есть два ортогональных параметра константности:

Можно ли начать указывать на другой объект?

Можно ли изменять объект, на который указывается?

Предложение на базе пары других, более старых предложений, предлагает для этого ввести новый cv-qualifier propconst (propagating const).

Этот квалификатор будет использоваться с указательными/ссылочными типами:

В предложении приведена таблица конвертации propconst в разных случаях.

2021: Constexpr-классы

2019-∞: Интерпретатор констант в компиляторе

С 2019 года в Clang разрабывается ConstantInterpeter, который в перспективе может полностью заменить вычислитель констант на синтаксическом дереве. Он довольно интересен и заслуживал бы отдельной статьи.

Его идея состоит в том, что на основе синтаксического дерева можно сгенерировать «байткод», который затем выполнить на интерпретаторе. Интерпретатор поддерживает в себе стек, фреймы вызовов, модель памяти (с метаданными, о которых говорилось ранее).

Документация для ConstantInterpeter хорошая, и также много интересного есть в видео-выступлении создателя интерпретатора на конференции LLVM-разработчиков.

Что можно еще посмотреть?

Для того, чтобы больше расширить понимание, можно посмотреть замечательные выступления от экспертов. В каждом выступлении авторы выходят за рамки рассказа про constexpr: это может быть построение constexpr-библиотеки; рассказ про использование constexpr в будущем reflexpr; или про устройство вычислителя констант и интерпретатора констант.

constexpr ALL the things!, Ben Deane & Jason Turner, C++Now 2017. Уже немного устарело, но может быть интересно, про построение constexpr-библиотеки.

Compile-time programming and reflection in C++20 and beyond, Louis Dionne, CppCon 2018. Много внимания уделяется будущей рефлексии в C++.

Полезный constexpr, Антон Полухин (@antoshkka), C++ CoreHard Autumn 2018. Есть про компиляторы, рефлексию и метаклассы.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *