член статических данных constexpr без инициализатора - PullRequest
0 голосов
/ 01 июня 2018
#include <complex>

struct S
{
  static std::complex<double> constexpr c;
};

gcc выдает ошибку, поскольку инициализатор отсутствует.Clang и MSVC не генерируют ошибку.

Насколько я знаю, член статических данных constexpr должен иметь инициализатор, даже если он имеет тип класса, который имеет конструктор, который можно вызывать без аргументов (как вэтот случай).К сожалению, у меня нет последнего стандарта C ++ для подтверждения моего предположения.

Поэтому правильный код должен инициализироваться конструктором, например:

struct S
{
  static std::complex<double> constexpr c {};
};

Может кто-нибудь доказать, какой компиляторправильно, а что неправильно?

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

В данном конкретном случае существует два ответа:

  • Для C ++ 14 gcc равен right (т.е. элемент статических данных constexpr должениметь инициализатор).
  • Для C ++ 17 и выше, gcc - неправильно , так как он отказывается компилировать соответствующий код.

Прежний регистр : в черновике N3797 (C ++ 14 ), 9.4.2.3 (члены-статические данные) [class.static.data] (выделено мной):

A static член данных литеральный тип может быть объявлен в определении класса с помощью спецификатора constexpr;если это так, его объявление должно указывать скобка или равный инициализатор , в котором каждое предложение инициализатора , которое является выражением присваивания является константным выражением.

См. также: http://en.cppreference.com/w/cpp/language/static#Constant_static_members.

Я сказал "в этом конкретном случае", потому что std::complex имеетспециализация для double, то есть LiteralType.Поэтому вышеупомянутое правило применяется.Об общих (то есть не литеральных) типах см. ответ кодекайзеров .

Последний регистр : для C ++ 17 см. xskxzr ответ .

0 голосов
/ 01 июня 2018

GCC не так.

GCC использует правила C ++ 14 для constexpr переменных, что требует инициализации.Это изменяется для P0386 (текст, выделенный полужирным шрифтом, является вновь добавленным текстом):

В 9.2.3.2p3, измените:

Еслиэнергонезависимый n встроенный const статический член данных имеет целочисленный тип или тип перечисления, его объявление в определении класса может указывать ab race-or-equal-initializer в котором каждое предложение инициализатора , которое является выражением присваивания , является константным выражением (5.20). Статический член данных литерального типа может быть объявлен в определении класса с помощью спецификатора constexpr;если это так, в его объявлении должна быть указана инициализация-скобка или равный-инициализатор, в которой каждое предложение-инициализатор, являющееся выражением присваивания, является константным выражением.[Примечание: в обоих этих случаях член может появляться в константных выражениях.- примечание конца] Элемент все еще должен быть определен в области пространства имен, если он используется в программе с помощью odr (3.2), и определение области пространства имен не должно содержать инициализатор. A n inline staticэлемент данных может быть определен в определении класса и может указывать b race-or-equal-initializer . Если элемент объявлен с помощью спецификатора constexpr, он может быть повторно объявлен в области пространства имен без инициализатора(это использование устарело; см. DX).Объявления других элементов статических данных не должны указывать b race-or-equal-initializer .

0 голосов
/ 01 июня 2018

С dcl.constexpr # 1 :

Функция или static элемент данных, объявленный со спецификатором constexpr, неявно является функцией или переменной inline

constexpr static члены данных неявно inline.

Также из class # static.data-3 , выделение шахта:

inline static элемент данных может быть определен в определении class, а может указать brace-or-equal-initializer.


Таким образом, GCC неверен.brace-or-equal-initializer является не строго обязательным .

Ссылка: N4659 C ++ 17 Черновик

...