Question

Le programme suivant compile:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage

int main()
{
    Test<&var> test;
}

Celui-ci, cependant, ne le fait pas, ce qui est une surprise pour moi:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage
extern const int * const ptr = &var; //extern needed to force external linkage
int main()
{
    Test<ptr> test; //FAIL! Expected constant expression.
}

Exemple alternatif:

int main()
{
   const int size = 42;
   int ok[*&size]; //OK

   const int * const pSize = &size;
   int fail[*pSize]; //FAIL
}

J'ai conclu qu'un pointeur ne peut tout simplement pas être une expression constante, qu'elle soit constante et initialisée avec une expression constante.

Des questions:

  1. Ma conclusion est-elle vraie?
  2. Si oui, pourquoi un pointeur ne peut-il pas être une expression constante? Sinon, pourquoi les programmes ci-dessus ne se compilent-ils pas?
  3. C ++ 0x (C ++ 11, si vous voulez) change-t-il quelque chose?

Merci pour tous les idées!

Était-ce utile?

La solution

C'est un peu plus compliqué. Dans C ++ 03 et C ++ 11, &var est une expression constante si var est une variable locale statique / classe statique ou de la portée de l'espace de noms. C'est ce qu'on appelle une expression constante d'adresse. L'initialisation d'une variable de pointeur statique ou d'espace de noms de noms avec cette expression constante est garantie avant tout code exécuté (phase d'initialisation statique), car il s'agit d'une expression constante.

Cependant seulement depuis C ++ 11, un constexpr variable du pointeur qui stocke l'adresse &var Peut également être utilisé comme une expression constante d'adresse et uniquement depuis C ++ 11, vous pouvez déréférence d'une expression constante d'adresse (en fait, vous pouvez désintéresser encore plus - même Une variable intégrale constante initialisée avant la déréférence ou une variable constexpr, vous obtenez à nouveau une expression constante (en fonction de la catégorie de type et de valeur, le type d'expression constante peut varier). En tant que tel, ce qui suit est valide C ++ 11:

int const x = 42;
constexpr int const *px = &x;

// both the value of "px" and the value of "*px" are prvalue constant expressions
int array[*px];
int main() { return sizeof(array); }

Si oui, pourquoi un pointeur ne peut-il pas être une expression constante? Sinon, pourquoi les programmes ci-dessus ne se compilent-ils pas?

Il s'agit d'une limitation connue dans le libellé de la norme - il n'autorise actuellement que d'autres paramètres de modèle comme des arguments ou & object, pour un paramètre de modèle de type de pointeur. Même si le compilateur devrait être capable d'en faire beaucoup plus.

Autres conseils

Il n'est toujours pas autorisé dans C ++ 0x. temp.arg.nontype a besoin:

Un argument de modèle pour un paramètre de modèle non-modèle non type doit être l'un des:

  • Pour un paramètre de matrice non de type de type intégral ou d'énumération, une expression constante convertie (5.19) du type du paramètre de matrice; ou
  • le nom d'un paramètre de modèle non de type; ou
  • Une expression constante (5.19) qui désigne l'adresse d'un objet avec durée de stockage statique et une liaison externe ou interne ou une fonction avec une liaison externe ou interne, y compris les modèles de fonction et les modèles de fonctions de fonction mais excluant les membres de la classe non statique, exprimé (ignorant les parenthèses) comme & id-expression, sauf que le & peut être omis si le nom fait référence à une fonction ou un tableau et doit être omis si le paramètre de modèle correspondant est une référence; ou
  • une expression constante qui évalue à une valeur de pointeur nulle (4.10); ou
  • une expression constante qui évalue à une valeur de pointeur de membre nul (4.11); ou
  • Un pointeur vers le membre exprimé comme décrit dans 5.3.1.

Réponse originale:

  1. Dans C ++ 03, seules les expressions intégrales peuvent être des expressions constantes.
  2. Parce que la norme le dit (naturellement).
  3. En C ++ 0x, N3290 comprend des exemples en utilisant constexpr sur un pointeur. Donc, ce que vous essayez devrait maintenant être possible, bien que vous deviez maintenant utiliser le constexpr mot-clé au lieu de haut niveau const.

Il y a aussi un bogue GCC impliqué, G ++ rejette les propres exemples du projet standard de valide constexpr usage.

Le problème est que votre programme C ++ peut être chargé à tout moment en mémoire, et donc l'adresse d'un global var Peut être différent à chaque fois que vous exécutez le programme. Que se passe-t-il si vous exécutez votre programme deux fois? var est évidemment dans deux endroits différents alors.

Pire encore, dans votre exemple, vous prenez l'adresse d'une variable sur la pile! regarde ça:

void myfunction( unsigned int depth) {
     const int myvar = depth;
     const int * const myptr = &myvar;
     if (depth)
         myfunction(depth-1);
}

Si principal appelle MyFunction (3), alors 3 myvars sont créés à des emplacements séparés. Il n'y a aucun moyen pour le temps de compilation de savoir comment de nombreux Les myvars sont créés, encore moins dans des emplacements exacts.

Enfin: déclarer une variable const signifie: "je promets", et fait ne pas signifie que c'est une constante de temps de compilation. Voir cet exemple:

int main(int argc, char** argv) {
    const int cargc = argc;
    char* myargs[cargc]; //the size is constant, but not a _compile time_ constant.
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top