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

В C ++ 11 и C ++ 14 для чего нужен constexpr в следующем fragmentе:

 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; 

    2 Solutions collect form web for “Инициализатор константного выражения для статического члена classа типа double”

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

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

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

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

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

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

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

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

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

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

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

    Определяя ваши статические константные переменные вне classа, вы сигнализируете компилятору, что это реальное определение – реальный экземпляр с памятью.

    Давайте будем гением компьютера.