J'ai une classe qui contient essentiellement un tas de définitions constantes utilisées dans mon application. Pour une raison quelconque cependant, long
s compile mais float
s ne fait pas:
class MY_CONSTS
{
public :
static const long LONG_CONST = 1; // Compiles
static const float FLOAT_CONST = 0.001f; // C2864
};
Donne l'erreur suivante:
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
Suis-je en train de manquer quelque chose?
Pour répondre à la question que vous avez posée: "parce que la norme le dit".
Seules les variables de types statique, constant, intégral (y compris les énumérations) peuvent être initialisées à l'intérieur d'une déclaration de classe. Si un compilateur prend en charge l'initialisation en ligne des flottants, il s'agit d'une extension. Comme d'autres l'ont souligné, la façon de traiter les variables statiques, constantes et non intégrales consiste à les définir et à les initialiser dans le fichier source correspondant de la classe (et non dans l'en-tête).
C++ Standard Section 9.2 "Class Members" item 4:
Un membre-déclarant peut contenir un constant-initializer uniquement s'il déclare un membre statique (9.4) de type const intégrale ou const enumeration, voir 9.4.2.
Section 9.4.2 "Membres de données statiques", élément 2:
Si un membre de données statiques est de type const intégrale ou const énumération, sa déclaration dans la définition de classe peut spécifier un constant-initializer qui doit être une expression constante intégrale (5.19). Dans ce cas, le membre peut apparaître dans des expressions constantes intégrales. Le membre doit toujours être défini dans une étendue d'espace de noms s'il est utilisé dans le programme et la définition d'étendue d'espace de noms ne doit pas contenir un initialiseur.
Vous devez les initialiser dans le corps de l'un de vos fichiers 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;
Voir explication de Stroustrup . Citation pertinente:
Une classe est généralement déclarée dans un fichier d'en-tête et un fichier d'en-tête est généralement inclus dans de nombreuses unités de traduction. Cependant, pour éviter les règles de l'éditeur de liens compliquées, C++ requiert que chaque objet ait une définition unique. Cette règle serait violée si C++ permettait la définition en classe d'entités qui devaient être stockées en mémoire en tant qu'objets. Voir D&E pour une explication des compromis de conception de C++.
La justification sous le libellé standard que d'autres ont donné est la même pour laquelle les arguments de modèle ne peuvent pas être des nombres à virgule flottante. Pour obtenir un résultat cohérent, vous aurez besoin que le compilateur implémente la même évaluation que celle effectuée au moment de la compilation, ce qui peut être compliqué pour le compilateur croisé et dans le cas où le programme joue avec le mode d'arrondi.
De la mémoire, en C++ 0X, la notion d'expression constante a été étendue et donc votre code serait valide (mais il n'est pas spécifié dans le résultat des expressions constantes à virgule flottante sont les mêmes lors de l'évaluation au moment de l'exécution ou au moment de la compilation) ).
qu'en est-il de:
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;
(cependant, je ne peux donner aucune explication sur ce cas spécifique ...)
De la norme 9.4.2/4
Si un membre de données statiques est de type const intégrale ou const enumeration, sa déclaration dans la définition de classe peut spécifier un initialiseur constant qui doit être une expression constante intégrale (5.19). Dans ce cas, le membre peut apparaître dans des expressions constantes intégrales. Le membre doit toujours être défini dans une étendue d'espace de noms s'il est utilisé dans le programme et la définition d'étendue d'espace de noms ne doit pas contenir d'initialiseur.
Et 5.19/1:
À plusieurs endroits, C + + nécessite des expressions qui s'évaluent en une constante intégrale ou d'énumération: en tant que limites de tableau (8.3.4, 5.3.4), en tant qu'expressions de cas (6.4.2), en tant que longueurs de champ de bits (9.6), comme initialiseurs d'énumérateur (7.2), en tant qu'initialiseurs de membre statique (9.4.2), et en tant qu'arguments de modèle de type non intégral ou d'énumération (14.3). expression-constante: expression-conditionnelle Une expression-constante intégrale ne peut impliquer que des littéraux (2.13), des énumérateurs, des variables const ou des membres de données statiques de type intégral ou énumération initialisés avec des expressions constantes (8.5), des paramètres de modèle non-type d'intégrale ou d'énumération types et taille des expressions. Les littéraux flottants (2.13.3) ne peuvent apparaître que s'ils sont convertis en types intégraux ou d'énumération. Seules les conversions de types en types intégraux ou d'énumération peuvent être utilisées. En particulier, sauf dans la taille des expressions, les fonctions, les objets de classe, les pointeurs ou les références ne doivent pas