IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

argument dependent name lookup


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 290
    Billets dans le blog
    2
    Par défaut argument dependent name lookup
    Bonjour tout le monde,

    est-ce que quelqu'un aurait une idée du "pourquoi" de cette ... chose?
    Je m'explique.
    Considérons le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // code trouvé sur http://www.mycppquiz.com mais un peu modifié
     
    #include <iostream>
     
    namespace standards
    {
        struct datastructure
        {
        };
     
        void foo(const datastructure& ds)
        {
        }
    }
     
    int main(int argc, char** argv)
    {
        standards::datastructure ds;
     
        foo(ds);
     
        return 0;
    }
    Et bien ce code fonctionne. C'est à dire que malgré qu'on appelle la fonction foo en dehors du namespace et sans le spécifier, le compilateur trouve quand-même la fonction à appeler. Grâce justement à ce fameux "argument dependent name lookup" (ou Koenig lookup). D'ailleurs comment doit-on traduire ça en français?

    Si j'ai bien compris, le principe c'est qu'il parvient à identifier la fonction en utilisant le namespace de son paramètre.

    Mais je trouve ça super nul en fait: à quoi bon utiliser des espaces de nommage si on peut les court-circuiter ainsi?
    Et puis ça peut être dangereux non? On pourrait par exemple, porté par l'enthousiasme d'avoir savamment découpé notre programme en namespaces clairs et explicites, et implémenter 2 fonctions ayant le même nom, mais déclarées et définies dans des namespaces différents, et là c'est le drame: on ne peux jamais être vraiment certain de laquelle de ces 2 fonctions va être appelée finalement. Non?

    Enfin, je voulais poster cette "réflexion" ici car j'imagine que si ça a été fait ainsi, en plus c'est dans le standard (3.4.2), il doit bien y avoir de bonnes raisons. En savez-vous plus sur ce sujet?

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Il y a une bonne raison (et plein de bonnes raisons pour ne pas le faire, mais elle ne suffisent pas à contrecarrer la première) :

    Comment trouver la fonction operator<< située dans l'espace de nom std quand on écrit
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 290
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Il y a une bonne raison (et plein de bonnes raisons pour ne pas le faire, mais elle ne suffisent pas à contrecarrer la première) :

    Comment trouver la fonction operator<< située dans l'espace de nom std quand on écrit
    Merci pour la réponse Loic, mais je ne comprends pas
    Il suffit d'écrire Ou utiliser using namespace std;
    Ce que l'on fait habituellement d'ailleurs, non?

    Citation Envoyé par gl
    J'avoue avoir du mal à trouver un cas où on ne saurait pas quelle fonction va être appeler.
    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // fichier UdpServer.h
    namespace UdpServer
    {
       void SendNumber( int number );
    } 
     
    // fichier TcpServer.h
    namespace TcpServer
    {
       void SendNumber( double number );
    }
     
    // main
     
    #include "TcpServer.h"
    #include "UdpServer.h"
     
    // on va utiliser surtout le TcpServer, donc pour plus de confort, on inclus le namespace:
    using namespace TcpServer;
     
    int main()
    {
       // déclaration de diverses variables. L'idée étant d'avoir un code avec plein de variables, ce qui peut engendrer une erreur d'inattention
       int a,b,c;
       double e,f,g;
       // du code
       SendNumber( c ); // Et là c'est le drame: c est un int, c'est donc SendNumber de l'UpdServer qui est appelé
    }
    Bon ok, c'est tiré par les cheveux, mais c'est pour trouver un cas simple.

  4. #4
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Citation Envoyé par r0d Voir le message
    Merci pour la réponse Loic, mais je ne comprends pas
    Il suffit d'écrire Ou utiliser using namespace std;
    Ce que l'on fait habituellement d'ailleurs, non?

    Non même si tu écris std::cout << 12; tu as le même problème sans ADL. Imagine la forme complète de l'opérateur :

    operator<<(std::cout, 12);


    Tu vois mieux le problème là ?

  5. #5
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par r0d Voir le message
    Merci pour la réponse Loic, mais je ne comprends pas
    Il suffit d'écrire Ou utiliser using namespace std;
    Ce que l'on fait habituellement d'ailleurs, non?
    Non, ici tu donnes le namespace de l'opérande cout, pas de l'opérateur <<. Et c'est justement l'ADL qui permet de retrouver l'opérateur à utiliser en fonction des opérandes..

    Citation Envoyé par r0d Voir le message
    Par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // fichier UdpServer.h
    namespace UdpServer
    {
       void SendNumber( int number );
    } 
     
    // fichier TcpServer.h
    namespace TcpServer
    {
       void SendNumber( double number );
    }
     
    // main
     
    #include "TcpServer.h"
    #include "UdpServer.h"
     
    // on va utiliser surtout le TcpServer, donc pour plus de confort, on inclus le namespace:
    using namespace TcpServer;
     
    int main()
    {
       // déclaration de diverses variables. L'idée étant d'avoir un code avec plein de variables, ce qui peut engendrer une erreur d'inattention
       int a,b,c;
       double e,f,g;
       // du code
       SendNumber( c ); // Et là c'est le drame: c est un int, c'est donc SendNumber de l'UpdServer qui est appelé
    }
    Non, ici c'est bien celui de TcpServer qui est appelé, int n'est pas un type défini dans le namespace UdpServer. Si tu passes en paramètre un type défini dans le namespace UdpServer, effectivement tu vas utiliser le SendNumber de UdpServer mais ça reste parfaitement défini.

    Et je ne vois pas de cas où le comportement n'est pas parfaitement défini ni ne donne d'erreur de compilation. Que ce ne soit pas facile de voir rapidement quelle fonction sera appelée, oui je suis tout à fait d'accord. Mais je ne vois pas de cas où on ne peut pas le savoir.

  6. #6
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 290
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 290
    Billets dans le blog
    2
    Par défaut
    Ouille aille, oui je me suis emberlificôté les pinceaux. J'ai du mal en ce moment (il faut dire que je ne code pas du tout depuis quelques semaines).

    Oui maintenant je comprend pour le cout. Effectivement. Merci pour vos explications.

  7. #7
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    L'ADL est assez cool mais assez dangereux. Ca permets de faire des trucs comme boost::swap et parfois aussi de se vautrer mechamment a cause de quelques corner cases.

    L'ADL regarde aussi les namespaces des types passer en parametre template d'une classe pour choisir son jeu de namespace. Blague lorsque on fait une fonction size(T) qui prend en parametre un objet avec un mpl::int_ en parametre template et que le compilo couine que mpl::size n'est pas une fonction :E

    Au niveau bibliotheque, je prends soin de toujours full-qualifié mes appels internes pour maitriser le tout. Par contre, il est important de laisser l'ADL jouer pour la partie user API

  8. #8
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Citation Envoyé par r0d Voir le message
    Bonjour tout le monde,

    est-ce que quelqu'un aurait une idée du "pourquoi" de cette ... chose?
    Ce qu'a dis Loic . Et oui l'ADL c'est _chiant_ mais c'est "indispensable". D'autant plus qu'a d'autre niveau y'a des bug bien plus subtile qui peuvent apparaitre...
    Si tu veux cour-circuiter l'ADL tu peux utiliser des ADL-barriers (ou qualifié tes appels :p.)

    Mais quand même, c'est pratique dans bon nombre de cas.

  9. #9
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Il y a une article sur le sujet sur GotW (de Sutter donc), le titre c'est peut-eter (j'ai un doute), "What is in a class ? he Interface Principle".

    L'argumentation c'est qu'une classe ce n'est pas juste ce qu'il y a entre les 2 accolades après l'identifiant de la classe. Mais aussi toute les fonctions libre associés, du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void foo(MaClass&);
    A ce moment vient se greffer l'idée des namespaces, ils servent à regrouper ensemble ce qui est sémantiquement (volontairement ambigue ici) proche. Donc en particulier tout les éléments d'une classe (en particulier les fonctions libres) doivent se retrouver ensemble.

    Et là l'idée du Koenig Lookup permet lorsque tu utilises une fonction (libre) sur un objet, de chercher dans toute l'interface de l'objet, donc dans le namespace de l'argument.

  10. #10
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par r0d Voir le message
    Mais je trouve ça super nul en fait: à quoi bon utiliser des espaces de nommage si on peut les court-circuiter ainsi?
    Et puis ça peut être dangereux non? On pourrait par exemple, porté par l'enthousiasme d'avoir savamment découpé notre programme en namespaces clairs et explicites, et implémenter 2 fonctions ayant le même nom, mais déclarées et définies dans des namespaces différents, et là c'est le drame: on ne peux jamais être vraiment certain de laquelle de ces 2 fonctions va être appelée finalement. Non?
    J'avoue avoir du mal à trouver un cas où on ne saurait pas quelle fonction va être appeler. J'imagine bien des cas où il y a ambiguïté, mais aucun où je ne me fais pas jeter par le compilateur à ce sujet. Aurais-tu un exemple ?

  11. #11
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Ce genre de problèmatique touche principalement les développeurs de bibliothèques, pas les end user.

Discussions similaires

  1. template template et name dependent lookup
    Par Kalith dans le forum Langage
    Réponses: 1
    Dernier message: 08/01/2014, 12h39
  2. RMI Naming.lookup
    Par tanguy.L dans le forum Langage
    Réponses: 4
    Dernier message: 23/04/2009, 14h16
  3. No function matches the given name and argument types.
    Par Davboc dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 03/05/2007, 11h25
  4. Skip-name-resolve - Impossible d'activer cet argument
    Par fenx06 dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 15/01/2007, 09h56
  5. Host name lookup failure
    Par rvfranck dans le forum Réseau
    Réponses: 1
    Dernier message: 24/04/2006, 15h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo