Инициализатор константных выражений для статического члена класса типа double

В C ++ 11 и C ++ 14 зачем мне constexpr в следующем фрагменте:

class Foo {
static constexpr double X = 0.75;
};

тогда как этот выдает ошибку компилятора:

class Foo {
static const double X = 0.75;
};

и (что более удивительно) это компилируется без ошибок?

class Foo {
static const double X;
};

const double Foo::X = 0.75;

12

Решение

В C ++ 03 нам было разрешено предоставлять только инициализатор класса для статических переменных-членов константного интеграла типов перечисления, в C ++ 11 мы могли инициализировать статический член литерального типа в классе с помощью constexpr. Это ограничение было сохранено в C ++ 11 для константных переменных, в основном для совместимости будет C ++ 03, мы можем видеть это из закрытый выпуск 1826: const с плавающей точкой в ​​константных выражениях который говорит:

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

CWG закрыла этот запрос как не дефект (NAD), в основном говоря:

что программисты, желающие, чтобы значения с плавающей точкой участвовали в константных выражениях, должны использовать constexpr вместо const.

Для справки N1804 Наиболее близкий проект стандарта C ++ 03 общедоступный в разделе 9.4.2 [Class.static.data] говорит:

Если статический член данных имеет константный интеграл или константный тип перечисления, его объявление в определении класса может
задайте инициализатор константы, который должен быть выражением интегральной константы (5.19). В этом случае член может появиться
в интегральных константных выражениях. Член по-прежнему должен быть определен в области имен, если он используется в программе и
определение области пространства имен не должно содержать инициализатор.

и проект стандартного раздела C ++ 11 9.4.2 [Class.static.data] говорит:

Если энергонезависимый постоянный статический член данных имеет целочисленный тип или тип перечисления, его объявление в классе
в определении можно указать скобку-или-равный-инициализатор, в которой каждое предложение-инициализатор, являющееся выражением присваивания
является постоянным выражением (5.19). Статический член данных литерального типа может быть объявлен в
определение класса с помощью спецификатора constexpr; если это так, в его объявлении должна быть указана инициализация-скобка
в котором каждое предложение инициализатора, которое является выражением присваивания, является константным выражением. […]

это почти то же самое в проекте стандарта C ++ 14.

8

Другие решения

Статические константные «определения» в классе на самом деле являются объявлениями. Когда переменная определена, компилятор выделяет память для этой переменной, но здесь дело обстоит не так, то есть получение адреса этих объектов static-const-in-class плохо сформировано, NDR.

Эти вещи должны быть включены в код, но это не так легко сделать с типами с плавающей запятой, поэтому это недопустимо.

Определяя ваши статические константные переменные вне класса, вы сообщаете компилятору, что это реальное определение — реальный экземпляр с расположением в памяти.

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector