Что такое constexpr, constinit и consteval и чем они отличаются в C++
Что проверяют
Понимаете ли вы, что именно из перечисленного даёт гарантию, а что только разрешение. Три спецификатора звучат похоже, и без точного ответа сразу видно, читал человек стандарт или собирал знание по обрывкам.
Как отвечать
Разделяйте функции и переменные. На функции constexpr это разрешение: её можно вызвать в константном контексте, но с аргументом, известным только в рантайме, она спокойно посчитается в рантайме. На переменной constexpr требует инициализации константным выражением и заодно делает переменную константой.
consteval объявляет немедленную функцию: каждый её вызов обязан вычисляться на этапе компиляции, а попытка передать значение, не являющееся константным выражением, это ошибка сборки. Так пишут то, что не должно случайно уехать в рантайм.
constinit относится только к переменным со статическим или потоковым временем жизни и требует статической инициализации, то есть отсутствия динамической инициализации при старте программы. Это средство против неопределённого порядка инициализации между единицами трансляции. Константой переменную он при этом не делает.
constexpr int sq(int x) { return x * x; }
consteval int cube(int x) { return x * x * x; }
constinit int counter = sq(4);Короткая мнемоника: можно на компиляции, только на компиляции, инициализируется на компиляции.
Где спотыкаются
Утверждают, что constexpr гарантирует вычисление при сборке. Гарантия появляется лишь тогда, когда результат требуется в константном контексте: размер массива, аргумент шаблона, инициализация константной переменной. В остальных случаях выбор за компилятором, и проверять его надо явно.
Путают constinit с const и ждут, что помеченную переменную нельзя менять. Менять можно: спецификатор говорит только о способе инициализации, а не о неизменяемости.
Пытаются вызвать немедленную функцию из обычной, подставив её параметр. Параметр функции не является константным выражением даже внутри функции, помеченной как вычислимая на этапе компиляции, поэтому код не собирается. Это не дефект компилятора, а прямое следствие правил.