Qu'est-ce que “l'Argument Dépendante de la Recherche” (aka ADL, ou “Koenig de Recherche”)?
Quelles sont les bonnes explications sur l'argument qu'dépendante de la recherche? Beaucoup de gens l'appellent également Koenig de Recherche ainsi.
De préférence, j'aimerais savoir:
- Pourquoi est-il une bonne chose?
- Pourquoi est-ce une mauvaise chose?
- Comment ça fonctionne?
- gotw.ca/gotw/030.htm
- double possible de Pourquoi GCC permet l'appel de cette fonction sans utiliser son espace de noms en premier?
- C'est une bonne chose parce que Otherwise:
std::cout << "Hello world";
ne serait pas compiler - en.cppreference.com/w/cpp/language/adl
Vous devez vous connecter pour publier un commentaire.
Koenig Recherche, ou Argument Dépendante De Recherche, décrit comment les noms non qualifiés sont considérés par le compilateur en C++.
Le C++11 standard § 3.4.2/1 membres:
En termes plus simples, Nicolai Josuttis unis1:
Un exemple de code simple:
Dans l'exemple ci-dessus il n'y a ni
using
-déclaration ni unusing
-directive, mais encore le compilateur identifie correctement le nom sansdoSomething()
que la fonction déclarée dans l'espace de nomsMyNamespace
en appliquant Koenig recherche.Comment ça fonctionne?
L'algorithme indique au compilateur de ne pas seulement regarder une portée locale, mais aussi les espaces de noms qui contiennent de l'argument type. Ainsi, dans le code ci-dessus, le compilateur trouve que l'objet
obj
, qui est l'argument de la fonctiondoSomething()
, appartient à l'espace de nomsMyNamespace
. Ainsi, il semble à l'espace de noms pour localiser la déclaration dedoSomething()
.Quel est l'avantage de Koenig recherche?
Que le simple exemple de code ci-dessus montre, Koenig de recherche offre la commodité et la facilité d'utilisation pour le programmeur. Sans Koenig de recherche, il y aurait une surcharge sur le programmeur, à plusieurs reprises spécifier les noms entièrement qualifiés, ou au lieu de cela, utilisez de nombreux
using
-déclarations.Pourquoi la critique de Koenig recherche?
Dépendance excessive à l'égard Koenig recherche peut conduire à des problèmes sémantiques, et attraper le programmeur hors garde parfois.
Prenons l'exemple de
std::swap
, qui est une bibliothèque standard de l'algorithme pour échanger deux valeurs. Avec l'Koenig de recherche il faut être prudent lors de l'utilisation de cet algorithme car:ne peut pas afficher le même comportement que:
Avec l'ADL, la version de
swap
fonction est appelée dépendra de l'espace de noms des arguments passés.S'il existe un espace de noms
A
et siA::obj1
,A::obj2
&A::swap()
existe pas, alors le deuxième exemple se traduit par un appel àA::swap()
, ce qui pourrait ne pas être ce que l'utilisateur voulu.De plus, si pour une raison tout à la fois
A::swap(A::MyClass&, A::MyClass&)
etstd::swap(A::MyClass&, A::MyClass&)
sont définis, puis le premier exemple d'appelstd::swap(A::MyClass&, A::MyClass&)
mais la seconde ne sera pas compiler, carswap(obj1, obj2)
d'être ambigu.Trivia:
Pourquoi est-il appelé “Koenig de recherche”?
Parce qu'il a été conçu par l'ancien AT&T et Bell Labs chercheur et programmeur, Andrew Koenig.
Pour en savoir plus:
Herb Sutter est à la Recherche d'un Nom sur GotW
Standard C++03/11 [de base.de recherche.argdep]: 3.4.2 Argument dépendant de recherche de nom.
1 La définition de Koenig de recherche est tel que défini dans Josuttis livre, Le C++ Standard Library: Un Tutoriel et de Référence.
std::swap
vous avez réellement à faire car la seule alternative serait d'ajouterstd::swap
fonction de modèle explicite de spécialisation pour votreA
classe. Pourtant, si votreA
classe est un modèle lui-même, il serait partielle de la spécialisation plutôt qu'explicite la spécialisation. Et partielle de la spécialisation de la fonction de modèle n'est pas autorisé. L'ajout de la surcharge destd::swap
pourrait être une alternative, mais est explicitement interdit (vous ne pouvez pas ajouter des choses àstd
espace de noms). Donc ADL est de la seule moyen pourstd::swap
.std::swap()
semble un peu en arrière. Je m'attends à ce que le problème ne sera quandstd::swap()
est sélectionné plutôt que la surcharge de travail spécifique pour le type,A::swap()
. L'exemple avecstd::swap(A::MyClass&, A::MyClass&)
semble induire en erreur. depuisstd
ne serait jamais avez une surcharge pour un type d'utilisateur, je ne pense pas que c'est un excellent exemple.prog.cpp:(.text.startup+0x7): undefined reference to
MyNamespace::doSomething(MyNamespace::Maclasse)".MyNamespace::doSomething
, pas seulement::doSomething
.Dans Koenig de Recherche, si une fonction est appelée sans spécifier son espace de noms, le nom d'une fonction est aussi recherché dans l'espace de noms(s) dans laquelle le type de l'argument(s) est définie. C'est pourquoi il est également connu comme Argument Dépendant de Recherche de nom, bref,ADL.
C'est à cause de Koenig Recherche, nous pouvons écrire ceci:
Sinon, on aurait dû écrire:
qui est vraiment trop tapé et le code a l'air vraiment moche!
En d'autres termes, en l'absence de Koenig de Recherche, même un Bonjour tout le Monde programme s'annonce compliquée.
std::string
a été utilisé à la place d'un littéral de chaîne. Voir Koenig explication: drdobbs.com/cpp/a-personal-note-about-argument-dependent/...std::cout
est un argument à la fonction, ce qui est suffisant pour permettre l'ADL. Avez-vous remarqué?operator<<
pourconst char*
n'est pas un membre, mais une fonction globale. Donc Koenig est trompé. Puis j'ai pensé qu'il est peu probable que personne n'a remarqué si loin et si il y a des commentaires hargneux quelqu'un l'a déjà fait observer. Et je n'étais pas trompé. En effet, quelqu'un n'a fait observer. C'était vous! 😉 Désolé pour mon erreur, maintenant je me tiens corrigé!ostream<<
(comme dans ce qu'il prend comme arguments et de quoi il en retourne). 2) noms Entièrement qualifiés (commestd::vector
oustd::operator<<
). 3) Une étude plus détaillée de l'Argument Dépendante de Recherche.std::operator<<(std::operator<<(std::cout, s), std::endl);
devrait êtrestd::operator<<(std::cout, s).operator<<(std::endl);
, voir ideone.com/FFKA7bstd::endl
comme argument, est en fait une fonction membre. De toute façon, si j'utilise"\n"
au lieu destd::endl
, alors ma réponse est correcte. Merci pour le commentaire.std::operator<<(std::operator<<(std::cout, s), std::endl);
échoue lors de la compilation, mais Siendl
est remplacé par'\n'
puis il travaille? Allez-vous expliquer plus sur le sujet ?f(a,b)
appelle un gratuit de la fonction. Ainsi dans le cas destd::operator<<(std::cout, std::endl);
, il n'existe pas de telle fonction qui prendstd::endl
comme deuxième argument. C'est la fonction de membre qui prendstd::endl
comme argument, et pour laquelle vous devez écrirestd::cout.operator<<(std::endl);
. et puisqu'il y a un gratuit fonction qui prendchar const*
comme deuxième argument,"\n"
œuvres;'\n'
marcherait aussi bien.Peut-être qu'il est préférable de commencer avec la raison, et seulement ensuite à le faire.
Lorsque les espaces de noms ont été introduits, l'idée était d'avoir tout ce que définis dans des espaces de noms, de sorte que les bibliothèques distinctes n'interfèrent pas les uns avec les autres. Cependant, qui a introduit un problème avec les opérateurs. Regardez par exemple le code suivant:
Bien sûr, vous pourriez avoir écrit
N::operator++(x)
, mais qui aurait vaincu le point de l'ensemble de la surcharge d'opérateur. Par conséquent, une solution devait être trouvée, qui a permis le compilateur pour trouveroperator++(X&)
malgré le fait qu'il n'était pas dans le champ d'application. D'autre part, il reste ne devrait pas trouver un autreoperator++
définie dans un autre, sans rapport avec l'espace de noms susceptibles de faire l'appel ambigu (dans cet exemple simple, vous n'en aurez pas d'ambiguïté, mais dans les cas les plus complexes, vous pourriez). La solution a été Argument Dépendante de Recherche (ADL), appelé ainsi depuis la recherche dépend de l'argument (ou plus exactement, sur l'argument du type). Depuis que le programme a été inventé par Andrew R. Koenig, il est également souvent appelé Koenig de recherche.Le truc, c'est que pour les appels de fonction, en plus de la recherche de nom (qui trouve les noms dans le champ d'application au moment de l'utilisation), il est procédé à une deuxième recherche dans les champs de tous les types de arguments passés à la fonction. Ainsi, dans l'exemple ci-dessus, si vous écrivez
x++
en main, il semble pouroperator++
non seulement dans la portée globale, mais en plus dans le champ d'application lorsque le type dex
,N::X
, a été définie, c'est à dire dansnamespace N
. Et là, il trouve une correspondanceoperator++
, et doncx++
fonctionne, tout simplement. Un autreoperator++
définie dans un autre espace de noms, direN2
, ne sera pas trouvé, cependant. Depuis ADL n'est pas limitée à des espaces de noms, vous pouvez également utiliserf(x)
au lieu deN::f(x)
dansmain()
.Pas tout, c'est bon, à mon avis. Les gens, y compris les éditeurs de compilateurs, ont été insultant parce qu'il a parfois malheureusement ce comportement.
ADL est responsable d'une refonte complète de la gamme de boucle en C++11. Pour comprendre pourquoi l'ADL peut parfois avoir des effets inattendus, considèrent que non seulement les espaces de noms, où les arguments sont définis, sont considérés comme, mais aussi les arguments des arguments de modèle de l'argumentation, de types de paramètres de types de fonctions /pointee types de types de pointeur de ces arguments, et ainsi de suite.
Un exemple d'utilisation de boost
Ce qui a entraîné une ambiguïté si l'utilisateur utilise le boost.plage de la bibliothèque, parce que les deux
std::begin
est trouvé (par ADL à l'aide destd::vector
) etboost::begin
est trouvé (par ADL à l'aide deboost::shared_ptr
).std::begin
efface l'espace de noms de l'ambiguïté.