Почему статические константные числа не допускаются? - PullRequest
60 голосов
/ 16 марта 2010

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

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

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

Ответы [ 6 ]

56 голосов
/ 16 марта 2010

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

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

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

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

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

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

36 голосов
/ 16 марта 2010

Вы должны инициализировать их в теле одного из ваших файлов 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;
19 голосов
/ 16 марта 2010

См. Объяснение Страуструпа . Соответствующая цитата:

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

8 голосов
/ 16 марта 2010

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

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

3 голосов
/ 16 марта 2010

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

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

И 5,19 / 1:

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

3 голосов
/ 16 марта 2010

а как же:

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;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...