Que signifie «utiliser ODR» quelque chose?

92

Cela vient juste d'être soulevé dans le contexte d' une autre question .

Apparemment, les fonctions membres des modèles de classe ne sont instanciées que si elles sont utilisées par ODR. Quelqu'un pourrait-il expliquer ce que cela signifie exactement. L' article de wikipedia sur One Definition Rule (ODR) ne mentionne pas " ODR-use ".

Cependant, la norme le définit comme

Une variable dont le nom apparaît comme une expression potentiellement évaluée est utilisée par odr à moins qu'il ne s'agisse d'un objet qui satisfait aux exigences pour apparaître dans une expression constante (5.19) et que la conversion lvalue-en-rvalue (4.1) est immédiatement appliquée.

dans [basic.def.odr].

Edit: Apparemment, ce n'est pas la bonne partie et le paragraphe entier contient plusieurs définitions pour différentes choses. Cela peut être le plus pertinent pour la fonction membre du modèle de classe:

Une fonction non surchargée dont le nom apparaît comme une expression potentiellement évaluée ou un membre d'un ensemble de fonctions candidates, si elle est sélectionnée par résolution de surcharge lorsqu'elle est référencée à partir d'une expression potentiellement évaluée, est utilisée par odr, sauf s'il s'agit d'un pur virtuel fonction et son nom ne sont pas explicitement qualifiés.

Je ne comprends cependant pas, comment cette règle fonctionne sur plusieurs unités de compilation? Toutes les fonctions membres sont-elles instanciées si j'instancie explicitement un modèle de classe?

Sarien
la source
2
Notez que [basic.def.odr] / 6 s'applique aux fonctions membres des modèles de classe "Il peut y avoir plus d'une définition [...]"
dyp
3
"Toutes les fonctions membres sont-elles instanciées si j'instancie explicitement un modèle de classe?" Oui, voir [temp.explicit] / 8 + 9
dyp

Réponses:

71

C'est juste une définition arbitraire, utilisée par la norme pour spécifier quand vous devez fournir une définition pour une entité (par opposition à une simple déclaration). La norme ne dit pas simplement «utilisé», car cela peut être interprété différemment selon le contexte. Et certaines utilisations ODR ne correspondent pas vraiment à ce que l'on associerait normalement à «utiliser»; par exemple, une fonction virtuelle est toujours utilisée par ODR à moins qu'elle ne soit pure, même si elle n'est réellement appelée nulle part dans le programme.

La définition complète se trouve au §3.2 , deuxième paragraphe, bien qu'elle contienne des références à d'autres sections pour compléter la définition.

En ce qui concerne les modèles, l'utilisation de l'ODR n'est qu'une partie de la question; l'autre partie est l'instanciation. En particulier, le §14.7 traite du moment où un modèle est instancié. Mais les deux sont liés: alors que le texte du §14.7.1 (instanciation implicite) est assez long, le principe de base est qu'un modèle ne sera instancié que s'il est utilisé, et dans ce contexte, utilisé signifie utilisé ODR. Ainsi, une fonction membre d'un modèle de classe ne sera instanciée que si elle est appelée, ou si elle est virtuelle et que la classe elle-même est instanciée. Le standard lui-même compte sur cela dans de nombreux endroits: les std::list<>::sortutilisations <sur les éléments individuels, mais vous pouvez instancier une liste sur un type d'élément qui ne prend pas en charge <, tant que vous ne l'appelez pas sort.

James Kanze
la source
l'utilisation de l'ODR pourrait-elle chevaucher les «temporaires matérialisés»?
v.oddou
23

En clair, odr-used signifie que quelque chose (variable ou fonction) est utilisé dans un contexte où sa définition doit être présente.

par exemple,

struct F {
   static const int g_x = 2;
};

int g_x_plus_1 = F::g_x + 1; // in this context, only the value of g_x is needed.
                             // so it's OK without the definition of g_x

vector<int>  vi;
vi.push_back( F::g_x );      // Error, this is odr-used, push_back(const int & t) expect
                             // a const lvalue, so it's definition must be present

Remarque, le push_back ci-dessus passé dans MSVC 2013, ce comportement n'est pas conforme à la norme, les deux gcc 4.8.2 et clang 3.8.0 ont échoué, le message d'erreur est: référence non définie à `K :: g_x '

zhaorufei
la source
Est-il possible d'utiliser odr un membre de données statique comme vi.push_back( F::g_x );en C ++?
Rankaba
Mais une rvalue pourrait également être passée à const int&? Le membre statique const pourrait-il être ragarded en tant que rvalue?
scottxiao
8
+1 pour la phrase d'ouverture succincte: "En clair, odr-used signifie que quelque chose (variable ou fonction) est utilisé dans un contexte où sa définition doit être présente."
Paul Masri-Stone
1
Je ne comprends pas comment vous compilez ce code. Sont-ils dans la même TU?. Si c'est le cas, F :: g_x a déjà été défini auparavant push_back, bien sûr il passera. N'est-ce pas?
Lewis Chan
1
@bigxiao " une rvalue peut également être transmise " Oui et un objet temporaire est créé par le compilateur et la référence est liée à cet objet. OTOH lors du passage d'une lvalue qui signifie passer cet objet référencé par l'évaluation de la lvalue: lorsque vous passez une lvalue, vous pouvez vous attendre à ce que le paramètre de la fonction fasse référence à l'objet correct. Le compilateur ne créera pas de fichier temporaire. Si vous voulez un temporaire, créez-en un avec operator+.
curiousguy