А.4. constexpr-функции
Целые литералы, например 42, — это константные выражения. Равно как и простые арифметические выражения, например 23*2-4. Частью константного выражения могут быть также const-переменные любого целочисленного типа, которые сами инициализированы константным выражением:
const int i = 23;
const int two_i = i * 2;
const int four = 4;
const int forty_two = two_i - four;
Помимо использования константных выражений для инициализации переменных, которые могут использоваться в других константных выражениях, есть ряд случаев, где разрешается применять только константные выражения.
• Задание границ массива:
int bounds = 99; │ Ошибка, bounds — не константное
int array[bounds];←┘ выражение
const int bounds2 = 99;│ Правильно, bounds2 — константное
int array2[bounds2]; ←┘ выражение
• Задание значения параметра шаблона, не являющего типом:
template<unsigned size>
struct test {}; │ Ошибка, bounds —
│ не константное
test<bounds> is;←┘ выражение
test<bounds2 > ia2;←┐ Правильно, bounds2 —
│ константное выражение
• Задание непосредственно в определении класса инициализатора для переменной-члена класса целочисленного типа со спецификаторами static const:
class X {
static const int the_answer = forty_two;
};
• Употребление в инициализаторах встроенных типов или агрегатов, применяемых для статической инициализации:
struct my_aggregate {
int a;
int b;
};
static my_aggregate ma1 =│ Статическая
{ forty_two, 123 }; ←┘ инициализация
int dummy = 257; │ Динамическая
static my_aggregate ma2 = {dummy, dummy};←┘ инициализация
Такая статическая инициализация полезна для предотвращения зависимости от порядка инициализации и состояний гонки.
Всё это не ново и было описано еще в стандарте С++ 1998 года. Но в новом стандарте появилось и дополнение в части константных выражений — ключевое слово constexpr.
Ключевое слово constexpr применяется главным образом как модификатор функции. Если параметр и возвращаемое функцией значение удовлетворяют определенным условиям, а тело функции достаточно простое, то в ее объявлении можно указать constexpr и использовать функцию в константных выражениях. Например:
constexpr int square(int x) {
return x*x;
}
int array[square(5)];
В этом случае массив array будет содержать 25 значений, потому что функция square объявлена как constexpr. Конечно, из того, что функцию можно использовать в константном выражении, еще не следует, что любой случай ее использования автоматически будет константным выражением:
int dummy = 4; (1) Ошибка, dummy — не константное
int array[square(dummy)];←┘ выражение
В этом примере dummy не является константным выражением (1), поэтому не является таковым и square(dummy). Это обычный вызов функции, и, следовательно, для задания границ массива array его использовать нельзя.