Требуется ли спецификатор constexpr при объявлении статического члена constexpr, инициализированного вне класса? - PullRequest
0 голосов
/ 21 мая 2018

C ++ 17 §10.1.5 / 1 состояния:

Спецификатор constexpr должен применяться только к определению переменной или шаблона переменной илиобъявление функции или шаблона функции.Функция или член статических данных, объявленные с помощью спецификатора constexpr, неявно являются встроенной функцией или переменной (10.1.6).Если какое-либо объявление функции или шаблона функции имеет спецификатор constexpr, то все его объявления должны содержать спецификатор constexpr.

Аналогичный абзац существует в стандарте начиная с C ++ 11(§7.1.5 / 1), который цитируется в комментарии Ричарда Смита , в котором он утверждает, что стандарт C ++ не требует, чтобы спецификатор constexpr совпадал между объявление и определение переменной.Последнее утверждение вышеприведенного абзаца явно требует, чтобы спецификатор constexpr совпадал между объявлениями функции и шаблона функции , но не упоминает объявления переменных.

§10.1.5 / 9 состояния:

Спецификатор constexpr, используемый в объявлении объекта, объявляет объект как const.Такой объект должен иметь буквальный тип и должен быть инициализирован.В любом объявлении переменной constexpr полное выражение инициализации должно быть константным выражением (8.20).

Конечно, если у нас есть отдельное объявление и определение, они оба должны будут соответствоватьв const ness, независимо от того, требуется ли совпадение спецификаторов constexpr.

§12.2.3.2 / 2-3 говорит:

2 Объявление не встроенного статического члена данных в его определении класса не является определением и может иметь неполный тип, отличный от cv void.Определение статического члена данных, который не определен встроенным в определении класса, должен появиться в области пространства имен, включающей определение класса члена.В определении в области пространства имен имя члена статических данных должно быть квалифицировано по имени его класса с помощью оператора ::.Выражение initializer в определении элемента статических данных входит в область его класса (6.3.7).

3 Если энергонезависимые не встроенные const статические данныеэлемент имеет целочисленный тип или тип перечисления ... Если элемент объявлен с помощью спецификатора constexpr, он может быть повторно объявлен в области пространства имен без инициализатора (такое использование не рекомендуется; см. D.1).Объявления других элементов статических данных не должны указывать скобка-или-равно-инициализатор .

§D.1 / 1 читает:

Для совместимости с предыдущими международными стандартами C ++ элемент constexpr статических данных может быть избыточно объявлен вне класса без инициализатора.Это использование устарело.

Из которого мы можем сделать вывод, что если элемент объявлен со спецификатором constexpr, то область имен definition равнаизбыточность и выражение инициализатора должны быть в паре с объявлением и должны быть опущены в определении / переопределении .

В качестве полного примера я предлагаю случай статического члена его собственного класса литерального типа (который не может быть инициализирован в классе):

struct S
{
    static S const ZERO; // not marked `constexpr`, but still `const`

    constexpr S(int value = {}) : _value{ value } {}

    int const _value;
};

constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const`

Эта интерпретацияconstexpr Использование со статическими членами данных поддерживается GCC, Clang и MSVC, хотя Мне сказали, что это неправильно .

Является ли нарушение несоответствиемиспользование спецификатора constexpr в объявлениях и определениях переменных?

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

1 Ответ

0 голосов
/ 21 мая 2018

Если бы я прочитал это:

static S const ZERO; // not marked `constexpr`, but still `const`

S::ZERO никогда не изменит свое значение во время выполнения из-за const.

Однако:

constexpr S S::ZERO{ 0 }; // implicitly `inline` (if C++17) and `const`

Constant Evaluation выполняется для S::ZERO, который будет иметь постоянное целое значение 0 для _value.
Это вызывает ваше constexpr constructor:

constexpr S(int value = {}) : _value{ value } {}

Согласно basic.start.static - Инициализация константы :

константа-инициализатор для переменной или временного объекта o - это инициализатор, полное выражение которого является константным выражением , за исключением того, что если o является объектом, такой инициализаторможет также вызывать конструкторы constexpr для o и его подобъектов, даже если эти объекты имеют не-литеральные типы классов.

AND expr.const / 8.7 - Оценка константы :

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

Следовательно:

Является ли нарушением несоответствующее использование спецификатора constexpr в объявлениях и определениях переменных?

Я верю вашему кодув порядке.

...