Est-il judicieux d'utiliser des mots clés en ligne avec des modèles?

119

Étant donné que les modèles sont définis dans les en-têtes et que le compilateur est capable de déterminer si l'intégration d'une fonction est avantageuse, cela a-t-il un sens? J'ai entendu dire que les compilateurs modernes savent mieux quand intégrer une fonction et ignorent les inlineindices.


edit: Je voudrais accepter les deux réponses, mais ce n'est pas possible. Pour clore le problème, j'accepte la réponse de Phresnel , car elle a reçu la plupart des votes et il a formellement raison, mais comme je l'ai mentionné dans les commentaires, je considère les réponses de Puppy et Component 10 comme correctes aussi, d'un point de vue différent .

Le problème est dans la sémantique C ++, qui n'est pas stricte en cas de inlinemot clé et d'inlining. phresnel dit «écrivez en ligne si vous l'entendez», mais ce que l'on entend par là inlinen'est pas clair car il a évolué de sa signification originale à une directive qui «empêche les compilateurs de se plaindre des violations des ODR» comme le dit Puppy .

doc
la source

Réponses:

96

Ce n’est pas sans importance. Et non, tous les modèles de fonction ne le sont pas inlinepar défaut. Le standard est même explicite à ce sujet dans la spécialisation explicite ([temp.expl.spec])

Avoir les éléments suivants:

a.cc

#include "tpl.h"

b.cc

#include "tpl.h"

tpl.h (extrait de la spécialisation explicite):

#ifndef TPL_H
#define TPL_H
template<class T> void f(T) {}
template<class T> inline T g(T) {}

template<> inline void f<>(int) {} // OK: inline
template<> int g<>(int) {} // error: not inline
#endif

Compilez ceci, et voilà:

g++ a.cc b.cc
/tmp/ccfWLeDX.o: In function `int g<int>(int)':
inlinexx2.cc:(.text+0x0): multiple definition of `int g<int>(int)'
/tmp/ccUa4K20.o:inlinexx.cc:(.text+0x0): first defined here
collect2: ld returned 1 exit status

Ne pas indiquer inlinelors de l'instanciation explicite peut également entraîner des problèmes.

Donc, en résumé : pour les modèles de fonctions non entièrement spécialisés, c'est-à-dire ceux qui portent au moins un type inconnu, vous pouvez omettre inlineet ne pas recevoir d'erreurs, mais elles ne le sont toujours pas inline. Pour les spécialisations complètes, c'est-à-dire celles qui n'utilisent que des types connus, vous ne pouvez pas l'omettre.

Règle empirique proposée : écrivez inlinesi vous le pensez et soyez cohérent. Cela vous fait moins réfléchir à l'opportunité de le faire ou non simplement parce que vous le pouvez. (Cette règle de base est conforme au modèle C ++ de Vandevoorde / Josuttis : le guide complet ).

Sébastien Mach
la source
2
On aurait pu écrire, c'est vrai. Mais cela n'implique pas de cohérence, même si cela apparaît comme ça. Vandevoorde et Josuttis indiquent également exactement cela dans les modèles C ++: Le guide complet
Sebastian Mach
43
La spécialisation explicite n'est pas un modèle.
Puppy
2
@DeadMG: Pourtant, une fonction normale est préférée à une spécialisation complète lors de la recherche, donc si ce n'est pas un modèle, ni un modèle, que sont-ils alors?
Sebastian Mach
13
Cette réponse est incorrecte. Une spécialisation explicite d'un modèle est une fonction, pas un modèle. Cette fonction ne devient pas inlinesimplement parce que le modèle qui était spécialisé est marqué avec inline. Donc inline, le modèle est complètement hors de propos. Que cette fonction soit inlineou non n'a rien à voir avec sa génération via une spécialisation de modèle (et il y a de meilleures réponses que celle-ci: quand l'utiliser inline). La réponse de @Puppy ci-dessous est correcte, celle-ci ne l'est pas. L'ajout inlined'un modèle n'est pas pertinent et clang-tidyle supprimera en fait.
gnzlbg
6
De plus, l'exemple montre simplement les problèmes ODR pour les fonctions normales (le comportement n'a rien à voir avec les modèles). Pour tenter de montrer que ce inlinen'est pas sans importance, l'exemple doit couvrir le cas d'une spécialisation explicite template<> void f<>(int) {} sans le inlinemot - clé. Mais même dans ce cas, la modification du inlinespécificateur sur le modèle ne fait aucune différence, car le fait de marquer inlineou non le modèle n'a pas d'importance.
gnzlbg
34

Ce n'est pas pertinent. Tous les modèles le sont déjà inline- sans oublier qu'à partir de 2012, la seule utilisation du inlinemot-clé est d'empêcher les compilateurs de se plaindre des violations de l'ODR. Vous avez tout à fait raison - votre compilateur de génération actuelle saura tout seul ce qu'il faut insérer et peut probablement le faire même entre les unités de traduction.

Chiot
la source
11
La norme n'indique pas que tous les modèles sont en ligne.
Sebastian Mach
16
@phresnel: Mais les modèles ont la même sémantique que les inlinefonctions marquées (c'est-à-dire que plusieurs définitions équivalentes peuvent être passées à l'éditeur de liens, qui en sélectionnera une). Telle est la fonction réelle du inlinemot - clé , et non pas en ligne .
Ben Voigt
2
@BenVoigt: Je connais la signification de l'ODR inline. Jetez peut-être un coup d'œil à ma réponse ci-dessous (ou ci-dessus, selon le tri choisi). Pour les modèles non spécialisés, vous avez bien sûr raison, mais ce n'est formellement pas la même chose.
Sebastian Mach
3
@DeadMG: Il n'y a aucune exigence en C ++ qu'un modèle de fonction doit être implémenté dans un fichier d'en-tête; il peut être implémenté n'importe où. Pour refléter cela, j'ai tendance à recommander de baliser inlinece qui est censé être en ligne. Cela ne fait généralement aucune différence, mais en standard, ils ne sont pas identiques et ils ne sont pas tous en ligne. J'accepte votre position à ce sujet en disant "Ce n'est pas pertinent", mais selon la norme, tous les modèles ne sont pas en ligne, seulement pour vous en tant qu'utilisateur C ++ - ils apparaissent comme si.
Sebastian Mach
7
Votre commentaire sur la réponse acceptée selon laquelle la spécialisation explicite n'est pas un modèle (ce qui est évident après qu'on l'a dit, bien sûr ...) est peut-être la chose la plus utile sur cette page. Pourriez-vous également l'ajouter à votre réponse?
Kyle Strand
6

Comme vous l'avez suggéré, inlinec'est un indice pour le compilateur et rien de plus. Il peut choisir de l'ignorer ou, en fait, des fonctions en ligne non marquées en ligne.

Utiliser inlineavec des modèles était un moyen (médiocre) de contourner le problème que chaque unité de compilation créerait un objet séparé pour la même classe de modèle, ce qui causerait alors des problèmes de duplication au moment de la liaison. En utilisant inline(je pense) le nom mangling fonctionne différemment, ce qui contourne le conflit de nom au moment de la liaison, mais au détriment d'un code extrêmement gonflé.  

Marshall Cline l' explique ici mieux que moi.

Composant 10
la source
@Xeo: Ce n'était pas le cas auparavant. Vérifiez ici: gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/ ... Je suppose que cela a changé plus récemment, c'est pourquoi je parlais au passé.
Composant 10
2
@Xeo: Pouvez-vous m'indiquer la partie de The Standard qui stipule que les modèles de fonctions sont toujours en ligne? Parce qu'ils ne le sont pas.
Sebastian Mach
@phresnel: Intéressant, je pourrais jurer que j'ai lu cela dans la norme. Peut-être que je l'ai mélangé avec le fait que les modèles de fonction sont exemptés de l'ODR ( §14.5.5.1 p7 & p8). Mon mauvais, j'ai supprimé le mauvais commentaire.
Xeo
@Component 10 Pourquoi vous pensez que c'est un mauvais moyen de contourner le problème de compilation
Kapil