Почему статические константные числа не допускаются?

У меня есть класс, который по сути просто содержит набор константных определений, используемых в моем приложении. По какой-то причине, однако, long s компилируются, а float не:

class MY_CONSTS
{
public :
    static const long   LONG_CONST = 1;      // Compiles 
    static const float FLOAT_CONST = 0.001f; // C2864
};

Выдает следующую ошибку:

1>c:\projects\myproject\Constant_definitions.h(71) : error C2864: 'MY_CONSTS::FLOAT_CONST' : only static const integral data members can be initialized within a class

Я что-то упустил?

64
задан kennytm 16 March 2010 в 11:54
поделиться

6 ответов

Чтобы ответить на собственно вопрос, который вы задали: «потому что так говорит стандарт».

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

Раздел 9.2 стандарта C ++ «Члены класса», пункт 4:

объявитель-член может содержать инициализатор константы , только если он объявляет статический член (9.4) целочисленного типа или константного перечисления , см. 9.4.2.

Раздел 9.4.2 «Статические элементы данных», пункт 2:

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

59
ответ дан 24 November 2019 в 15:49
поделиться

а как насчет:

class MY_CONSTS
{
public :
    static const long   LONG_CONST;
    static const float FLOAT_CONST;
};

const long MY_CONSTS::LONG_CONST = 1;
const float MY_CONSTS::FLOAT_CONST = 0.001f;

(хотя я не могу дать никаких объяснений по этому конкретному случаю ...)

3
ответ дан 24 November 2019 в 15:49
поделиться

Вы должны инициализировать их в теле одного из ваших файлов cpp:

class MY_CONSTS
{
public :
    static const long   LONG_CONST = 1;      // Compiles 
    static const float FLOAT_CONST;
};

const float MY_CONSTS::FLOAT_CONST = 0.001f;
38
ответ дан 24 November 2019 в 15:49
поделиться

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

По памяти, в C++0X понятие константного выражения было расширено, поэтому ваш код будет корректен (но не уточняется, в результате константные выражения с плавающей точкой одинаковы при оценке во время выполнения или во время компиляции).

8
ответ дан 24 November 2019 в 15:49
поделиться

См. объяснение Страуструпа . quote:

Класс обычно объявляется в файле заголовка , а файл заголовка обычно включается во многие единицы перевода . Однако, чтобы избежать сложные правила компоновщика, C ++ требует , чтобы каждый объект имел уникальное определение. Это правило было бы нарушено , если бы C ++ допускал определение в классе сущностей, которые необходимы для хранения в памяти в виде объектов. См. объяснение компромиссов в дизайне C ++ в D&E.

19
ответ дан 24 November 2019 в 15:49
поделиться

Из стандарта 9.4.2/4

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

И 5.19/1:

В нескольких местах, C + + требует, чтобы выражения, которые оцениваются в интегралу или константе перечисления: как границы массивов (8.3.4, 5.3.4), как выражения case выражений (6.4.2), как битовые поля длины (9.6), как перечислитель инициализаторы (7.2), как статические члены инициализаторы (9.4.2), и как интегральные или перечисление не типа шаблона аргументы (14.3). константа-выражение: условное выражение Интегральное константное выражение может включать только литералы (2.13), перечислители, const переменные или статические члены данных интегральных или перечислительных типов инициализированные константными выражениями (8.5), параметры шаблона не типа интегральных типов или типов перечислений, и выражения sizeof. Плавающие литералы (2.13.3) могут появляться только в том случае, если они приведены к интегральному или перечислительным типам. Только тип преобразования к интегральным или перечислительным могут быть использованы. В частности, за исключением выражений sizeof, функции, объекты классов, указатели или ссылки не должны

3
ответ дан 24 November 2019 в 15:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: