У меня есть класс, который по сути просто содержит набор константных определений, используемых в моем приложении. По какой-то причине, однако, 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
Я что-то упустил?
Чтобы ответить на собственно вопрос, который вы задали: «потому что так говорит стандарт».
Только переменные статического, постоянного, целого типов (включая перечисления) могут быть инициализированы внутри объявления класса. Если компилятор поддерживает встроенную инициализацию чисел с плавающей запятой, это расширение. Как указывали другие, способ иметь дело со статическими, постоянными, нецелыми переменными состоит в том, чтобы определить и инициализировать их в соответствующем исходном файле класса (а не в заголовке).
Раздел 9.2 стандарта C ++ «Члены класса», пункт 4:
объявитель-член может содержать инициализатор константы , только если он объявляет статический член (9.4) целочисленного типа или константного перечисления , см. 9.4.2.
Раздел 9.4.2 «Статические элементы данных», пункт 2:
Если статический элемент данных имеет целочисленный или константный тип перечисления, его объявление в определении класса {{ 1}} может указывать инициализатор константы , который должен быть целочисленным константным выражением (5.19). В этом случае член может появляться в выражениях интегральных констант . Член все равно должен быть определен в области пространства имен, если он используется в программе, а определение области пространства имен не должно содержать инициализатор .
а как насчет:
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;
(хотя я не могу дать никаких объяснений по этому конкретному случаю ...)
Вы должны инициализировать их в теле одного из ваших файлов 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;
Обоснование стандартной формулировки, приведенное другими, является тем же самым, по которому аргументы шаблона не могут быть числами с плавающей точкой. Чтобы получить согласованный результат, нужно, чтобы компилятор реализовал ту же оценку, что и во время компиляции, а это может быть сложно для кросс-компилятора и в случае, когда программа играет с режимом округления.
По памяти, в C++0X понятие константного выражения было расширено, поэтому ваш код будет корректен (но не уточняется, в результате константные выражения с плавающей точкой одинаковы при оценке во время выполнения или во время компиляции).
См. объяснение Страуструпа . quote:
Класс обычно объявляется в файле заголовка , а файл заголовка обычно включается во многие единицы перевода . Однако, чтобы избежать сложные правила компоновщика, C ++ требует , чтобы каждый объект имел уникальное определение. Это правило было бы нарушено , если бы C ++ допускал определение в классе сущностей, которые необходимы для хранения в памяти в виде объектов. См. объяснение компромиссов в дизайне C ++ в D&E.
Из стандарта 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, функции, объекты классов, указатели или ссылки не должны