82 votes

enum vs constexpr réelles constantes statiques à l'intérieur des classes

Permettez-moi de commencer en disant à mon intention. Autrefois (C++) jours, nous avons un code comme:

class C
{
public:
  enum {SOME_VALUE=27};
};

Puis nous avons pu utiliser SOME_VALUE tout au long de notre code de la compilation constant et où le compilateur verrait C::SOME_VALUE, il suffit d'insérer le littéral 27.

De nos jours, il semble plus acceptable pour modifier ce code pour quelque chose comme:

class C
{
public:
  static constexpr int SOME_VALUE=27;
};

Cela ressemble beaucoup plus propre, donne SOME_VALUE un bien de type défini et semble être l'approche privilégiée comme du C++11. L' (imprévues au moins pour moi) le problème est que cela provoque également des scénarios où SOME_VALUE doit être externe. C'est, dans certains rpc fichier quelque part, nous devons ajouter:

constexpr int C::SOME_VALUE; // Now C::SOME_VALUE has external linkage

Le cas à l'origine de cette semblent être quand const références à SOME_VALUE sont utilisés, ce qui arrive assez souvent en C++ de la Bibliothèque Standard de code (Voir l'exemple au bas de cette question). Je suis en utilisant gcc 4.7.2 que mon compilateur par la voie.

En raison de ce dilemme, je suis obligé de revenir à la définition d' SOME_VALUE comme un enum (c'est à dire, de la vieille école) afin d'éviter d'avoir à ajouter une définition pour un fichier cpp pour certains, mais pas tous mes statique constexpr variables membres. N'est-il pas d'une certaine façon à indiquer au compilateur qu' constexpr int SOME_VALUE=27 signifie qu' SOME_VALUE doit être traitée seulement comme un moment de la compilation constante et jamais un objet avec une liaison externe? Si vous voyez un const référence utilisé avec elle, de créer un temporaire. Si vous voyez son adresse, de générer une erreur de compilation si il le faut, parce que c'est une compilation constante de temps et rien de plus.

Voici quelques apparence bénigne exemple de code qui fait que nous nous besoin d'ajouter la définition de l' SOME_VALUE dans un fichier cpp (encore une fois, testé avec gcc 4.7.2):

#include <vector>

class C
{
public:
  static constexpr int SOME_VALUE=5;
};

int main()
{
  std::vector<int> iv;

  iv.push_back(C::SOME_VALUE); // Will cause an undefined reference error
                               // at link time, because the compiler isn't smart
                               // enough to treat C::SOME_VALUE as the literal 5
                               // even though it's obvious at compile time
}

En ajoutant la ligne suivante dans le code à la portée de fichier peut résoudre l'erreur:

constexpr int C::SOME_VALUE;

9voto

apoorvkul Points 368

Vous avez trois possibilités:

  1. Si votre classe est un modèle, puis de les mettre à la définition de membre statique dans l'en-tête lui-même. Compilateur est nécessaire de l'identifier comme une seule définition à travers de multiples unités de traduction (voir [de base.def.odr]/5)

  2. Si votre classe est non-modèle, vous pouvez facilement le mettre dans le fichier source

  3. Sinon déclarer constexpr fonction membre statique getSomeValue():

    class C
    {
    public:
        static constexpr int getSomeValue() { return 27; }
    };
    

1voto

david.pfx Points 5594

À partir de la norme C++ N3797 S3.5/2-3

Un nom est dit avoir de liaison quand il peut désigner le même objet, de référence, de la fonction, le type, le modèle, l'espace de noms ou la valeur d'un nom introduit par une déclaration dans un autre champ d'application:

- Lorsqu'un nom a une liaison externe , l'entité qu'il désigne peut être désigné par les noms de portées d'autres unités de traduction ou à partir d'autres champs de la même unité de traduction.

- Lorsqu'un nom a une liaison interne , l'entité qu'il désigne peuvent être appelées par des noms à partir d'autres champs d'application dans la même unité de traduction.

- Quand le nom n'a pas de lien , l'entité qu'il désigne ne peut pas être désigné par les noms d'autres étendues.

Un nom ayant portée espace de noms (3.3.6) a une liaison interne si c'est le nom de

- une variable, une fonction ou une fonction modèle est explicitement déclarée statique; ou,

- non volatile variable qui est explicitement déclarée const ou constexpr et ni explicitement déclaré extern ni préalablement déclaré avoir une liaison externe; ou

- un membre de données d'un anonyme de l'union.

Ma lecture est que, dans le code suivant:

public:
  static constexpr int SOME_VALUE=5;
  constexpr int SOME_VALUE=5;
};
static constexpr int SOME_VALUE=5;
constexpr int SOME_VALUE=5;

Toutes les instances de 4 SOME_VALUE ont une liaison interne. Ils devraient être en lien avec une référence à l' SOME_VALUE dans la même unité de traduction et de ne pas être visible ailleurs.

Évidemment, la première est une déclaration et non une définition. Il a besoin d'une définition à l'intérieur de la même unité de traduction. Si GCC dit et MSVC n'en a pas, MSVC est faux.

Pour les fins du remplacement d'une enum, numéro 2 devrait fonctionner correctement. Il a encore de la liaison interne sans l' static mot-clé.

[Édité en réponse au commentaire]

1voto

J'irais avec enum class:

http://en.cppreference.com/w/cpp/language/enum

http://www.stroustrup.com/C++11FAQ.html#enum

À partir du premier lien:

enum class Color { RED, GREEN=20, BLUE};
Color r = Color::BLUE;
switch(r) {
    case Color::RED : std::cout << "red\n"; break;
    case Color::GREEN : std::cout << "green\n"; break;
    case Color::BLUE : std::cout << "blue\n"; break;
}
// int n = r; // error: no scoped enum to int conversion
int n = static_cast<int>(r); // OK, n = 21

0voto

Ophir Gvirtzer Points 281

vous pouvez le faire

class C
{
public:
  static const int SOME_VALUE=5;
};

int main()
{
  std::vector<int> iv;
  iv.push_back(C::SOME_VALUE); 
}

Ce n'est même pas de C++11, juste à C++98

0voto

edwinc Points 618

De nos jours, la meilleure façon est:

enum class : int C { SOME_VALUE = 5 };

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X