Je comprends que le paramètre de modèle non-type doit être une expression intégrale constante. Quelqu'un peut-il faire la lumière pourquoi en est-il ainsi?
template <std::string temp>
void foo()
{
// ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.
Je comprends ce qu'est une expression intégrale constante. Quelles sont les raisons de ne pas autoriser les types non constants comme std::string
comme dans l'extrait ci-dessus?
La raison pour laquelle vous ne pouvez pas le faire est que les expressions non constantes ne peuvent pas être analysées et substituées pendant la compilation. Ils pourraient changer pendant l'exécution, ce qui nécessiterait la génération d'un nouveau modèle pendant l'exécution, ce qui n'est pas possible car les modèles sont un concept au moment de la compilation.
Voici ce que la norme autorise pour les paramètres de modèle non-type (14.1 [temp.param] p4):
Un paramètre-modèle non-type doit avoir l'un des types suivants (éventuellement qualifiés par le cv):
- type intégral ou énumération,
- pointeur sur objet ou pointeur sur fonction,
- référence lvalue à l'objet ou référence lvalue à la fonction,
- pointeur vers le membre,
std::nullptr_t
.
Ce n'est pas permis.
Cependant, cela est autorisé:
template <std::string * temp> //pointer to object
void f();
template <std::string & temp> //reference to object
void g();
Voir §14.1/6,7,8 dans C++ Standard (2003).
Illustration:
template <std::string * temp> //pointer to object
void f()
{
cout << *temp << endl;
}
template <std::string & temp> //reference to object
void g()
{
cout << temp << endl;
temp += "...appended some string";
}
std::string s; //must not be local as it must have external linkage!
int main() {
s = "can assign values locally";
f<&s>();
g<s>();
cout << s << endl;
return 0;
}
Sortie:
can assign values locally
can assign values locally
can assign values locally...appended some string
Vous devez pouvoir manipuler les arguments de modèle
template <std::string temp>
void f() {
// ...
}
f<"foo">();
f<"bar">(); // different function!?
Maintenant, un impl doit avoir une séquence de caractères unique pour un std::string
ou, d'ailleurs, toute autre classe arbitraire définie par l'utilisateur, stockant une valeur particulière, dont la signification n'est pas connue de l'implémentation. De plus, la valeur des objets de classe arbitraires ne peut pas être calculée au moment de la compilation.
Il est prévu d'envisager d'autoriser les types de classes littérales en tant que types de paramètres de modèle pour le post-C++ 0x, qui sont initialisés par des expressions constantes. Celles-ci pourraient être modifiées en faisant en sorte que les membres de données soient modifiés de manière récursive en fonction de leurs valeurs (pour les classes de base, par exemple, nous pouvons appliquer une traversée en profondeur d'abord, de gauche à droite). Mais cela ne fonctionnera certainement pas pour les classes arbitraires.
Un argument de modèle non type fourni dans une liste d'arguments de modèle est une expression dont la valeur peut être déterminée au moment de la compilation. Ces arguments doivent être:
expressions constantes, adresses de fonctions ou d'objets avec liaison externe ou adresses de membres de classe statiques.
En outre, les littéraux de chaîne sont des objets avec une liaison interne, vous ne pouvez donc pas les utiliser comme arguments de modèle. Vous ne pouvez pas non plus utiliser un pointeur global. Les littéraux à virgule flottante ne sont pas autorisés, étant donné la possibilité évidente d'arrondir les erreurs.