70 votes

On peut utiliser un lambda dans les fichiers d'en-tête de violer l'ODR?

Peut la suite être écrit dans un fichier d'en-tête:

inline void f () { std::function<void ()> func = [] {}; }

ou

class C { std::function<void ()> func = [] {}; C () {} };

Je suppose que dans chaque fichier source, le lambda est peut être de type différent et, par conséquent, le contenu de type en std::function (target_type's résultats diffèrent).

Est-ce une ODR (Une Définition de la Règle) la violation, en dépit de ressembler à un modèle commun et une chose raisonnable à faire? Le deuxième exemple de violer l'ODR à chaque fois, ou seulement si au moins un constructeur est dans un fichier d'en-tête?

41voto

Columbo Points 11661

Cela se résume à savoir si ou non un lambda de type diffère à travers des unités de traduction. Si elle le fait, elle peut affecter argument de modèle de déduction et potentiellement provoquer des fonctions différentes pour être appelé dans ce qui sont destinés à être des définitions cohérentes. Qui serait en violation de l'ODR (voir ci-dessous).

Cependant, cela n'est pas prévu. En fait, ce problème a déjà été abordé il y a un moment par la question centrale 765, ce qui précisément les noms de fonctions en ligne, avec une liaison externe - comme f:

7.1.2 [dcl.fct.spec] le paragraphe 4 précise que les collectivités locales de variables statiques et les littéraux de chaîne apparaissant dans le corps d'une fonction en ligne avec liaison externe doivent être les mêmes entités dans chaque unité de traduction dans le cadre du programme. Rien n'est dit, cependant, au sujet de savoir si les types de sont également requis pour être la même.

Bien que conforme programme pourrait toujours déterminé par l'utilisation de typeid, les récentes modifications apportées à C++ (permettant de types locaux en tant que modèle les arguments de type lambda expression de fermeture de classes) de faire de cette question de plus en plus pressant.

Notes à partir du mois de juillet, 2009 de la réunion:

Les types sont destinés à être le même.

Maintenant, la résolution intègre la formulation suivante dans [dcl.fct.spec]/4:

Un type défini dans le corps d'un extern inline de la fonction est le même type dans chaque unité de traduction.

(NB: MSVC n'est pas le sujet du texte ci-dessus encore, même si elle pourrait dans la prochaine version).

Les Lambdas à l'intérieur de ces fonctions, que les corps sont donc sans danger, depuis la fermeture de ce type de définition est en effet au bloc de portée ([expr.prim.lambda]/3).
D'où de multiples définitions de l' f ont jamais été bien définies.

Cette résolution n'est certainement pas à couvrir tous les scénarios, car il existe de nombreux types d'entités avec une liaison externe qui peuvent faire usage de lambdas, les modèles de fonction, en particulier, devraient être couverts par une autre question essentielle.
Dans l'intervalle, Itanium contient déjà des règles appropriées pour s'assurer que ces lambdas " types coïncident dans plus de situations, d'où Clang et GCC devrait déjà pour la plupart se comportent comme prévu.


Standardese pourquoi différents types de fermeture sont une ODR de violation de la façon suivante. Envisager des points de balle (6.2) et (6.4) dans [de base.def.odr]/6:

Il peut y avoir plus d'une définition de [...]. Étant donné une telle entité nommée D défini dans plus d'une unité de traduction, chaque définition d' D est composé de la même séquence de jetons; et

(6.2) - dans chaque définition de l' D, correspondant noms, regarda vers le haut selon [de base.recherche], doit se référer à une entité définie dans la définition de l' D, ou se réfèrent à la même entité, après résolution de surcharge ([- dessus.match]) et après la mise en correspondance partielle modèle de spécialisation ([temp.sur]), [...]; et

(6.4) - dans chaque définition de l' D, la surcharge des opérateurs visés, l' implicite des appels à des fonctions de conversion, les constructeurs, opérateur de nouvelles fonctions et de suppression de l'opérateur fonctions, doit se référer à la même fonction, ou à une fonction définie dans la définition de l' D; [...]

Ce que cela signifie, c'est que toutes les fonctions appelées dans l'entité définition doit être le même dans toutes les unités de traduction - ou ont été définis à l'intérieur de sa définition, comme les classes locales et de leurs membres. I. e. l'utilisation d'un lambda n'est pas en soi problématique, mais en le passant à la fonction des modèles, il est clair, étant donné qu'elles sont définies à l'extérieur de la définition.

Dans votre exemple, avec C, la fermeture type est défini au sein de la classe (dont la portée est la plus petite en annexant une). Si la fermeture type diffère dans les deux TUs, la norme peut involontairement impliquer avec l'unicité d'une fermeture de type, le constructeur instancie et appelle différentes spécialisations de la functions'constructeur modèle, en violation de (6.4) dans la citation ci-dessus.

8voto

oliora Points 124

Mise à JOUR

Après tout, je suis d'accord avec @Columbo réponse, mais que vous voulez ajouter la pratique de cinq cents :)

Bien que l'ODR violation des sons dangereux, ce n'est pas vraiment un sérieux problème dans ce cas particulier. Le lambda classes créées dans différents TUs sont équivalentes sauf à leurs typeids. Donc, à moins que vous avez à faire avec le typeid d'un en-tête défini lambda (ou d'un type en fonction du lambda), vous êtes en sécurité.

Maintenant, lorsque l'ODR violation est signalé comme un bug, il ya une grande chance qu'il sera résolu dans les compilateurs qui ont le problème, par exemple, MSVC et probablement quelques autres ceux qui ne suivent pas l'Itanium ABI. Notez que Itanium ABI conforme compilateurs (par exemple gcc et clang) sont déjà en production ODR-bon code d'en-tête défini par les lambdas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X