Si un modèle de fonction a un type de retour déduit, existe-t-il un moyen de l'appeler sans instancier la définition?
Considérez un modèle de fonction tel que:
template <class T>
const auto& foo() { static T t; return t; }
La définition ne serait pas valide si T
c'était le cas void
. Néanmoins, nous sommes autorisés à instancier la déclaration seule sans déclencher d'erreur:
extern template const auto& foo<void>(); // explicit instantiation declaration
Considérons maintenant les situations où foo
est appelé, plutôt que d'être explicitement instancié. Évidemment, si elle foo
est appelée dans un contexte évalué, la définition de la spécialisation sera instanciée. Qu'en est-il dans un contexte non évalué? On sait que si un modèle de fonction avec un type de retour non déduit est appelé dans un contexte non évalué, la définition de la spécialisation n'est pas instanciée. L'exemple évident de ceci est std::declval<T>
. Il n'est pas clair si la même chose est possible pour une fonction qui a un type de retour déduit.
Par exemple, j'ai considéré ceci:
static_assert(sizeof( (void)foo<void>(), char{} ) == 1);
Cependant, même dans cette situation, où le compilateur a définitivement suffisamment d'informations pour évaluer l' sizeof
expression sans connaître le type de retour, une erreur de compilation se produit toujours ( lien godbolt ).
- Quelle disposition de la norme nécessite l'instanciation de la définition de
foo<void>
dans cette situation? - Existe-t-il un moyen qui
foo<void>
puisse être appelé à l'intérieur d'une expression non évaluée qui n'instancierait pas sa définition?
Réponses
Quelle disposition de la norme nécessite l'instanciation de la définition de
foo<void>
dans cette situation?
Bien que non normative, la note dans [dcl.spec.auto] / 11 mentionne que toute utilisation d'une spécialisation (d'un modèle de fonction avec un espace réservé dans son type de retour déclaré) provoquera une instanciation implicite [extrait, je souligne ] :
[...] [ Note: Par conséquent, toute utilisation d'une spécialisation du modèle de fonction provoquera une instanciation implicite.
et, de plus, [dcl.spec.auto] / 14 couvre le cas particulier de permettre une déclaration d'instanciation explicite sans déclencher d'instanciation, tout en laissant peut-être aussi entendre que les mécanismes d'instanciation déclenchés pour déterminer le type de retour pour un modèle de fonction sont quelque peu séparés de les mécanismes d'instanciation "réguliers" [c'est moi qui souligne ]:
Une déclaration d'instanciation explicite ne provoque pas l'instanciation d'une entité déclarée à l'aide d'un type d'espace réservé, mais elle n'empêche pas non plus que cette entité soit instanciée selon les besoins pour déterminer son type . [ Exemple:
template <typename T> auto f(T t) { return t; } extern template auto f(int); // does not instantiate f<int> int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit // instantiation definition is still required somewhere in the program
- fin d'exemple ]
où le commentaire (non normatif) à l'exemple indique qu'une telle instanciation implicite déclenchée dans un cas particulier n'est utilisée que pour la déduction de type de retour, et ne dispense pas de la nécessité d'une définition d'instanciation explicite ailleurs.
Existe-t-il un moyen qui
foo<void>
puisse être appelé à l'intérieur d'une expression non évaluée qui n'instancierait pas sa définition?
Compte tenu de la discussion ci-dessus, je dirais: non. L'appel même à l'intérieur d'une expression non évaluée relèverait du (non normatif) «toute utilisation de».