А.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 его использовать нельзя.