web-dev-qa-db-fra.com

Initialisation d'un membre const dans la déclaration de classe en C ++

Dans PHP et C #, les constantes peuvent être initialisées lorsqu'elles sont déclarées:

class Calendar3
{
    const int value1 = 12;
    const double value2 = 0.001;
}

J'ai la déclaration C++ suivante d'un foncteur qui est utilisé avec une autre classe pour comparer deux vecteurs mathématiques:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }

    static const float tolerance = 0.001;
};

Ce code compilé sans problèmes avec g ++. Maintenant en mode C++ 0x (-std = c ++ 0x) le compilateur g ++ génère un message d'erreur:

erreur: "constexpr" nécessaire pour l'initialisation en classe des données statiques "tolérance" de type non intégral

Je sais que je peux définir et initialiser cette static const membre en dehors de la définition de classe. De plus, un membre de données constant non statique peut être initialisé dans la liste d'initialisation d'un constructeur.

Mais existe-t-il un moyen d'initialiser une constante dans une déclaration de classe, comme cela est possible dans PHP ou C #?

Mise à jour

J'ai utilisé le mot clé static simplement parce qu'il était possible d'initialiser de telles constantes dans la déclaration de classe en g ++. J'ai juste besoin d'un moyen d'initialiser une constante dans une déclaration de classe, peu importe si elle est déclarée comme static ou non.

71
ezpresso

En C++ 11, non -static membres de données, static constexpr membres de données, et static const Les données membres de type intégrale ou énumération peuvent être initialisées dans la déclaration de classe. par exemple.

struct X {
    int i=5;
    const float f=3.12f;
    static const int j=42;
    static constexpr float g=9.5f;
};

Dans ce cas, le membre i de toutes les instances de la classe X est initialisé à 5 par le constructeur généré par le compilateur et le membre f est initialisé à 3.12. Le static const Le membre de données j est initialisé à 42, et le static constexpr Le membre de données g est initialisé à 9.5.

Puisque float et double ne sont ni de type intégral ni d’énumération, ces membres doivent être soit constexpr, soit non-static pour que l’initialiseur de la la définition de classe est autorisée.

Avant C++ 11, uniquement static const Les membres de données de type intégral ou énumération pourraient avoir des initialiseurs dans la définition de classe.

120
Anthony Williams

L'initialisation de variables membres statiques autres que les types const int n'est pas une norme C++ antérieure à C++ 11. Le compilateur gcc ne vous préviendra pas (et produira néanmoins du code utile) à moins que vous ne spécifiiez le -pedantic option. Vous devriez alors avoir une erreur similaire à:

const.cpp:3:36: error: floating-point literal cannot appear in a constant-expression
const.cpp:3:36: warning: ISO C++ forbids initialization of member constant ‘tolerance’ of non-integral type ‘const float’ [-pedantic]

La raison en est que la norme C++ ne spécifie pas comment la virgule flottante doit être implémentée et est laissée au processeur. Pour contourner cela et d'autres limitations, constexpr a été introduit.

43
Florian

Oui. Ajoutez simplement le mot clé constexpr comme le dit l'erreur.

11
StilesCrisis

Si vous n'en avez besoin que dans l'une des méthodes, vous pouvez le déclarer localement statique:

struct equal_vec
{
    bool operator() (const Vector3D& a, const Vector3D& b) const
    {
        static const float tolerance = 0.001f;
        Vector3D dist = b - a;
        return ( dist.length2() <= tolerance );
    }
};
1
Peter Wood

Cela me posait de réels problèmes, car j’avais besoin du même code pour compiler des versions différentes de g ++ (le compilateur GNU C++). Il me fallait donc utiliser une macro pour voir quelle version du compilateur a été utilisé, puis agissez en conséquence, comme si

#if __GNUC__ > 5
 #define GNU_CONST_STATIC_FLOAT_DECLARATION constexpr
#else
 #define GNU_CONST_STATIC_FLOAT_DECLARATION const
#endif

GNU_CONST_STATIC_FLOAT_DECLARATION static double yugeNum=5.0;

Ceci utilisera 'const' pour tout ce qui était antérieur à g ++ version 6.0.0, puis 'constexpr' pour g ++ version 6.0.0 et ultérieure. C'est un deviner à la version où le changement a lieu, parce que franchement je ne l'avais pas remarqué jusqu'à la version g ++ 6.2.1. Pour le faire correctement, vous devrez peut-être regarder la version mineure et le numéro de correctif de g ++.

https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html

pour plus de détails sur les macros disponibles.

Avec gnu, vous pouvez aussi vous en tenir à utiliser 'const' partout puis compiler avec le -fpermissive drapeau, mais cela donne des avertissements et j'aime bien compiler proprement mes affaires.

Pas génial, car il est spécifique aux compilateurs GNU, mais je suppose que vous pourriez faire la même chose avec d’autres compilateurs.

1
nilesOien