В первом примере d
не инициализируется константным выражением, поскольку S::c
не является
энергонезависимым константным объектом с предшествующей инициализацией, инициализированным константным выражением
(см. C ++ 11 [expr.const] p2, маркер для преобразования lvalue-в-значение), потому что инициализация S::c
не предшествует инициализации d
.Поэтому статическая инициализация будет использоваться для S::c
(поскольку она инициализируется константным выражением), но динамическая инициализация может использоваться для d
.
Поскольку статическая инициализация предшествует динамической инициализации, d
будетинициализируется 50
его динамическим инициализатором.Компилятору разрешено преобразовывать динамическую инициализацию d
в статическую инициализацию, но если это так, он должен выдавать значение, которое d
имел бы, если бы каждая переменная, которая могла бы использовать динамическую инициализацию, фактически использовала динамическуюинициализация.В этом случае d
инициализируется в 50
в любом случае.См. C ++ 11 [basic.start.init] p2 для получения дополнительной информации об этом.
Нет способа добавить constexpr
в первый пример, чтобы гарантировать, что статическая инициализация используется для d
;чтобы сделать это, вы должны изменить порядок инициализации.Однако добавление constexpr
приведет к диагностике для первого примера, которая, по крайней мере, позволит вам убедиться, что динамическая инициализация не используется (вы получаете статическую инициализацию или ошибку компиляции).
Вы можете обновить второй случай, чтобы обеспечить статическую инициализацию следующим образом:
struct S {
static const int c; // do not use constexpr here
};
constexpr int S::c = 5;
constexpr int d = 10 * S::c;
Неверно использовать constexpr
в объявлении переменной, которое не является определением, или использоватьэто в объявлении переменной, которое не содержит инициализатора, поэтому const
, а не constexpr
должно использоваться в определении struct S
.Из этого правила есть одно исключение: при определении элемента данных static constexpr
литерального нецелого типа с инициализатором, указанным в классе:
struct T { int n; };
struct U {
static constexpr T t = { 4 };
};
constexpr T U::t;
В этом случае constexpr
должен использоваться в определении класса, чтобы разрешить предоставление инициализатора, а constexpr
должен использоваться в определении статического члена данных, чтобы разрешить его использование в константных выражениях.