Константная инициализация
Устанавливает начальные значения статических переменных в константу времени компиляции.
Синтаксис
static T & ссылка = constexpr;
|
(1) | ||||||||
static T объект = constexpr;
|
(2) | ||||||||
Объяснение
Константная инициализация выполняется вместо инициализации нулём статических и локальных к потоку (начиная с C++11) объектов и перед всеми другими инициализациями. Только следующие переменные инициализируются константами:
|
3) Статический или локальный к потоку объект классового типа, который инициализируется вызовом конструктора, если конструктор является constexpr и все аргументы конструктора (включая неявные преобразования) являются константными выражениями, и если инициализаторы в списке инициализаторов конструктора и инициализаторы в фигурных скобках или равенства элементов класса содержат только константные выражения.
|
(начиная с C++11) |
Эффекты константной инициализации такие же, как эффекты соответствующей инициализации, за исключением того, что гарантируется, что она будет завершена до любой другой инициализации статического или локального к потоку (начиная с C++11) объекта, и она может быть выполнена во время компиляции.
Примечание
Компилятору разрешается инициализировать другие статические и локальные к потоку (начиная с C++11) объекты, используя константную инициализацию, если она может гарантировать, что значение будет таким же, как если бы следовал стандартный порядок инициализации.
На практике константная инициализация выполняется во время компиляции, а предварительно вычисленные представления объектов сохраняются как часть образа программы (например, в разделе .data). Если переменная инициализирована как const, так и константой инициализацией, её объектное представление может быть сохранено в разделе образа программы, доступном только для чтения (например, в разделе .rodata).
Пример
#include <iostream>
#include <array>
struct S
{
static const int c;
};
const int d = 10 * S::c; // неконстантное выражение: S::c не имеет предшествующего
// инициализатора, её инициализация происходит после const
const int S::c = 5; // константная инициализация, которая гарантированно
// произойдёт первой
int main()
{
std::cout << "d = " << d << '\n';
std::array<int, S::c> a1; // OK: S::c константное выражение
// std::array<int, d> a2; // ошибка: d не является константным выражением
}
Вывод:
d = 50
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| CWG 441 | C++98 | ссылки не могут быть инициализированы константно | сделаны константно инициализируемыми |
| CWG 1489 | C++98 | было неясно, может ли инициализация значением объекта быть константной инициализацией |
может |
| CWG 1747 | C++98 | привязка ссылки к функции не может быть константной инициализацией |
может |
| CWG 1834 | C++11 | привязка ссылки к xvalue не может быть константной инициализацией |
может |
| CWG 2026 | C++98 | было указано, что инициализация нулём всегда происходит первой, даже до константной инициализации |
нет инициализации нулём, если применяется константная инициализация |
| CWG 2366 | C++98 | инициализация по умолчанию не могла быть константной инициализацией (требовались константные инициализаторы) |
может |