const статический элемент данных без инициализатора
#include <complex>
struct S
{
static std::complex<double> constexpr c;
};
gcc генерирует ошибку, поскольку отсутствует инициализатор. Clang и MSVC не генерируют ошибку.
Насколько я знаю, статический элемент constexpr должен иметь инициализатор, даже если он имеет тип класса, который имеет конструктор, который можно вызывать без аргументов (как в этом случае). К сожалению, у меня нет последнего стандарта C++ для подтверждения моего предположения.
Поэтому правильный код должен инициализироваться конструктором, например:
struct S
{
static std::complex<double> constexpr c {};
};
Может ли кто-нибудь доказать, какой компилятор прав, а что неправильно?
Ответы
Ответ 1
GCC ошибочен.
GCC использует правила С++ 14 для переменных constexpr
, для которых требуется инициализатор. Это изменяется на P0386 (полужирный текст - это новый текст):
В 9.2.3.2p3 измените:
Если элемент non -volatile n on- inline const - статический элемент данных является интегральным или перечисляемым типом, его объявление в определении класса может указывать инициализатор ab race-or- equal-, в котором каждый пункт initializer- То есть выражение assignment- является постоянным выражением (5.20). Статический член данных типа literal может быть объявлен в определении класса с помощью спецификатора constexpr; если это так, в его декларации указывается скобка-равность -initializer, в которой каждое предложение initializer-, которое является присваиванием -expression, является постоянным выражением. [Примечание. В обоих случаях член может отображаться в постоянных выражениях. - конечная нота] Член еще быть определен в области видимости пространства имен, если это odr- используется (3.2) в программе, и определение области видимости пространства имен не должно содержать инициализатор. Статический член данных п инлайн может быть определен в определении класса и может указывать ab race-or-equal -initializer. Если член объявлен с помощью спецификатора constexpr, он может быть переопределен в области пространства имен без инициализатора (это использование устарело, см. DX). Объявления других статических данных не должны указывать ab race-or-equal -initializer.
Ответ 2
В этом конкретном случае есть два ответа:
- Для C++ 14 gcc прав (т.е. Constexpr статический член данных должен иметь инициализатор).
- Для C++ 17 и выше gcc ошибается, поскольку он отказывается компилировать соответствующий код.
Бывший случай: В проекте N3797 (C++ 14), 9.4.2.3 (Элементы статических данных) [class.static.data] (основное внимание):
static
член данных типа literal может быть объявлен в определении класса с constexpr
спецификатора constexpr
; если это так, в его декларации указывается логический или равный-инициализатор, в котором каждое предложение-инициализатор, являющееся выражением-присваиванием, является постоянным выражением.
См. Также: http://en.cppreference.com/w/cpp/language/static#Constant_static_members.
Я сказал "в этом конкретном случае", потому что std::complex
имеет специализацию для double
которая является LiteralType
. Поэтому применяется правило выше. Для общих (то есть нелиберальных) типов см. Ответ на кодкайзеры.
Последний случай: для C++ 17 см. Xskxzr ответ.
Ответ 3
Из dcl.constexpr # 1:
Функция или static
член данных, объявленный с constexpr
спецификатора constexpr
неявно является inline
функцией или переменной
constexpr
static
члены данных неявно inline
.
Также из класса # static.data-3, акцент мой:
inline
static
элемент данных может быть определен в определении class
и может указывать brace-or-equal-initializer
.
Таким образом, GCC ошибочен. не требуется строгое brace-or-equal-initializer
выравнивание.
Ссылка: N4659 С++ 17 Черновик