Использование переменной constinit для инициализации переменной constexpr - PullRequest
5 голосов
/ 02 октября 2019

Посмотрите на этот маленький пример:

constinit int a = 0;
constexpr int b = a;

clang не компилирует его ( godbolt ):

2: 15: error: constexprпеременная 'b' должна быть инициализирована константным выражением

Это правильная диагностика?

Если да, почему стандарт не допускает этого? Я понимаю, что значение a может изменяться во время работы (или даже во время динамической инициализации), но при постоянной инициализации его значение известно, поэтому его можно использовать для инициализации b.

Ответы [ 3 ]

3 голосов
/ 02 октября 2019

Да, диагностика правильная. constexpr переменные должны быть инициализированы с помощью константного выражения, а a не является константным выражением (это изменяемая переменная).

Цель constinit ( P1143 ) - этозаставить объявление переменной быть некорректным, если initialization не является константой. Он ничего не меняет в самой переменной, как, например, ее тип или что-то еще (в том смысле, что constexpr неявно const). Глупый пример:

struct T {
    int i;
    constexpr T(int i) : i(i) { }
    T(char c) : i(c) { }
};

constinit T c(42); // ok
constinit T d('X'); // ill-formed

Это все, для чего constinit, и единственное реальное правило - [dcl.constinit] / 2 :

Если переменная, объявленная с помощью спецификатора constinit, имеет динамическую инициализацию ([basic.start.dynamic]), программа некорректна. [ Примечание : спецификатор constinit обеспечивает инициализацию переменной во время статической инициализации ([basic.start.static]). - конечная нота ]

Константа в constinit относится только к инициализации, а не к переменной и не к каким-либо типам. Обратите внимание, что он также не меняет тип выполняемой инициализации, он просто диагностирует, если выполняется неправильный тип.

In:

constinit int a = 0;
constexpr int b = a;

0 является константным выражением, поэтому инициализация a является корректной. Как только мы преодолеем это, спецификатор ничего не сделает. Это эквивалентно:

int a = 0; // same behavior, a undergoes constant initialization
constexpr int b = a;

Это просто плохо сформировано.

но при постоянной инициализации его значение известно, поэтому его можно использовать для инициализации b.

Конечно, в данный момент. Как насчет:

constinit int a = 0;
cin >> a;
constexpr int b = a;

Это явно не полетит. Разрешение этого потребовало бы расширения того, что является константным выражением (на мой взгляд, это уже самое сложное правило в стандарте), чтобы разрешить непостоянные переменные, но только сразу после инициализации? Сложность не стоит того, так как вы всегда можете написать:

constexpr int initializer = 0;
constinit int a = initializer;
constexpr int b = initializer;
2 голосов
/ 02 октября 2019

constexpr объединяет constinit и const без исключения.

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

const запрещает изменение переменной, хотя может быть ослаблено mutable членами.

Оба вместе сделайте это константным выражением во время компиляции.

Таким образом, да, диагностика верна.

1 голос
/ 02 октября 2019

это правильная диагностика?

Я бы сказал, да. Согласно cppreference :

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

Статическая (постоянная) инициализация и постоянное выражение - это разные понятия в том смысле, что постоянное выражение может использоваться при постоянной инициализации , но не наоборот . constinit не следует путать с const . Это означает, что инициализация (только) постоянна.

Однако constinit const может использоваться в constexpr, и они должны быть одинаковыми.

Контрпример:

constinit int a = 0;

struct X{
    X() {
        a = 4;
    }
};

X x{};

constexpr int b = a;

Что такое b? Дело в том, что a можно изменить неконстантными способами, прежде чем b станет видимым .

...