Je crois comprendre que C ++ permet aux membres const statiques d'être définis à l'intérieur d'une classe tant qu'il s'agit d'un type entier.
Pourquoi, alors, le code suivant me donne-t-il une erreur de l'éditeur de liens?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
L'erreur que j'obtiens est:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Fait intéressant, si je commente l'appel à std :: min, le code se compile et se lie très bien (même si test :: N est également référencé sur la ligne précédente).
Une idée de ce qui se passe?
Mon compilateur est gcc 4.4 sous Linux.
c++
static
declaration
definition
HighCommander4
la source
la source
char
, vous pouvez le définir à la place commeconstexpr static const char &N = "n"[0];
. Notez le&
. Je suppose que cela fonctionne parce que les chaînes littérales sont définies automatiquement. Je suis un peu inquiet à ce sujet cependant - il pourrait se comporter étrangement dans un fichier d'en-tête parmi différentes unités de traduction, car la chaîne sera probablement à plusieurs adresses différentes.inline const int N = 10
, qui à ma connaissance a encore un stockage quelque part défini par l'éditeur de liens. Le mot clé en ligne pourrait également être utilisé dans ce cas pour fournir une définition de variable statique dans le test de définition de classe.Réponses:
Je crois comprendre que C ++ permet aux membres const statiques d'être définis à l'intérieur d'une classe tant qu'il s'agit d'un type entier.
Vous avez en quelque sorte raison. Vous êtes autorisé à initialiser des intégrales const statiques dans la déclaration de classe, mais ce n'est pas une définition.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr038.htm
Fait intéressant, si je commente l'appel à std :: min, le code se compile et se lie très bien (même si test :: N est également référencé sur la ligne précédente).
Une idée de ce qui se passe?
std :: min prend ses paramètres par référence const. Si cela les prenait par valeur, vous n'auriez pas ce problème, mais comme vous avez besoin d'une référence, vous avez également besoin d'une définition.
Voici le chapitre / verset:
9.4.2 / 4 - Si un
static
membre de données est de typeconst
intégral ouconst
énumération, sa déclaration dans la définition de classe peut spécifier un initialiseur de constante 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 portée d'espace de noms s'il est utilisé dans le programme et la définition de portée d'espace de noms ne doit pas contenir d' initialiseur .Voir la réponse de Chu pour une solution de contournement possible.
la source
5
à unconst int&
. Alors pourquoi ne pas traiter les OPtest::N
comme le littéral correspondant?L'exemple de Bjarne Stroustrup dans sa FAQ C ++ suggère que vous avez raison et que vous n'avez besoin d'une définition que si vous prenez l'adresse.
Il dit "Vous pouvez prendre l'adresse d'un membre statique si (et seulement si) il a une définition hors classe" . Ce qui suggère que cela fonctionnerait autrement. Peut-être que votre fonction min invoque en quelque sorte des adresses dans les coulisses.
la source
std::min
prend ses paramètres par référence, c'est pourquoi une définition est requise.template<class K, class V, class C> const typename AE<K,V,C>::KeyContainer::size_type AE<K,V,C>::c7;
où KeyContainer est un typedef de std :: vector <K>. Il faut lister tous les paramètres du modèle et écrire le nom du type car c'est un type dépendant. Peut-être que quelqu'un trouvera ce commentaire utile. Cependant, maintenant je me demande comment exporter cela dans une DLL car la classe de modèle est bien sûr dans un en-tête. Dois-je exporter c7 ???Une autre façon de faire cela, pour les types entiers de toute façon, est de définir des constantes comme des énumérations dans la classe:
la source
Pas seulement des int. Mais vous ne pouvez pas définir la valeur dans la déclaration de classe. Si tu as:
dans le fichier .h, vous devez avoir:
dans le fichier .cpp.
la source
static const
membre intégral dans la définition de classe. Mais cela ne définit toujours pas ce membre. Voir la réponse de Noah Roberts pour plus de détails.Voici une autre façon de contourner le problème:
(Je pense que la réponse de Crazy Eddie décrit correctement pourquoi le problème existe.)
la source
std::min(9, +test::N);
À partir de C ++ 11, vous pouvez utiliser:
static constexpr int N = 10;
Cela vous oblige théoriquement toujours à définir la constante dans un fichier .cpp, mais tant que vous n'en prenez pas l'adresse,
N
il est très peu probable qu'une implémentation du compilateur produise une erreur;).la source
Non, 3.1 §2 dit:
la source