Question

Quelqu'un peut-il expliquer pourquoi le code suivant ne compile pas? Au moins sur g ++ 4.2.4.

Et plus intéressant encore, pourquoi compilera-t-il lorsque jetterai MEMBER sur int?

#include <vector>

class Foo {  
public:  
    static const int MEMBER = 1;  
};

int main(){  
    vector<int> v;  
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}
Était-ce utile?

La solution

Vous devez réellement définir le membre statique quelque part (après la définition de la classe). Essayez ceci:

class Foo { /* ... */ };

const int Foo::MEMBER;

int main() { /* ... */ }

Cela devrait supprimer la référence non définie.

Autres conseils

Le problème vient d’un conflit intéressant entre les nouvelles fonctionnalités C ++ et ce que vous essayez de faire. Voyons d’abord la signature push_back :

void push_back(const T&)

Il attend une référence à un objet de type T . Sous l'ancien système d'initialisation, un tel membre existe. Par exemple, le code suivant compile parfaitement:

#include <vector>

class Foo {
public:
    static const int MEMBER;
};

const int Foo::MEMBER = 1; 

int main(){
    std::vector<int> v;
    v.push_back( Foo::MEMBER );       // undefined reference to `Foo::MEMBER'
    v.push_back( (int) Foo::MEMBER ); // OK  
    return 0;
}

Cela est dû au fait qu’il existe un objet réel quelque part dans lequel cette valeur est stockée. Si, toutefois, vous passez à la nouvelle méthode de spécification de membres const stat, comme ci-dessus, Foo :: MEMBER n'est plus un objet. C'est une constante, un peu semblable à:

#define MEMBER 1

Mais sans les maux de tête d’une macro de préprocesseur (et avec le type safety). Cela signifie que le vecteur qui attend une référence ne peut pas en obtenir une.

La norme C ++ requiert une définition pour votre membre const statique si la définition est nécessaire.

La définition est obligatoire, par exemple si son adresse est utilisée. push_back prend son paramètre par référence de const. Le compilateur a donc strictement besoin de l'adresse de votre membre et vous devez la définir dans l'espace de noms.

Lorsque vous convertissez explicitement la constante, vous créez un temporaire et c'est ce temporaire qui est lié à la référence (selon des règles spéciales dans la norme).

C’est un cas vraiment intéressant, et j’estime qu’il est utile de soulever un problème afin que le std soit modifié afin d’avoir le même comportement que votre membre constant!

Bien que, étrangement, cela puisse être perçu comme une utilisation légitime de l'opérateur unaire '+'. Fondamentalement, le résultat de unary + est une valeur rvalue. Les règles de liaison des valeurs rvalues ??aux références const s'appliquent et nous n'utilisons pas l'adresse de notre membre const statique:

v.push_back( +Foo::MEMBER );

Aaa.h

class Aaa {

protected:

    static Aaa *defaultAaa;

};

Aaa.cpp

// You must define an actual variable in your program for the static members of the classes

static Aaa *Aaa::defaultAaa;

Vous ne savez pas pourquoi la distribution fonctionne, mais Foo :: MEMBER n'est alloué que lorsque Foo est chargé pour la première fois, et comme vous ne le chargez jamais, il n'est jamais alloué. Si vous aviez une référence à un Foo quelque part, cela fonctionnerait probablement.

Concernant la deuxième question: push_ref prend la référence en tant que paramètre et vous ne pouvez pas avoir de référence à un membre statique de la classe / structure. Une fois que vous appelez static_cast, une variable temporaire est créée. Et une référence à cet objet peut être transmise, tout fonctionne parfaitement.

Ou du moins mon collègue qui a résolu ce problème l'a dit.

Avec C ++ 11, ce qui précède serait possible pour les types de base tels que

class Foo {
public:  
  static constexpr int MEMBER = 1;  
};

La partie constexpr crée une expression statique par opposition à une variable statique - et se comporte exactement comme une définition de méthode inline extrêmement simple. L'approche s'est toutefois révélée un peu bancale avec constexprs C-string dans les classes de modèle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top