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

C++ Discussion :

surcharge de fonction qui provoque une ambiguïté


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut surcharge de fonction qui provoque une ambiguïté
    Bonjour,
    Voici un petit code tout simple qui ne compile pas
    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
    template<class Chr>
    void pointer_or_array(Chr const *rs)
    {
    	std::cout << rs << " size: ?" << std::endl;
    }
     
    template<class Chr, size_t Rswz>
    void pointer_or_array(Chr const (&rs)[Rswz])
    {
    	std::cout << rs << " size: " << Rswz << std::endl;
    }
     
    int main()
    {
    	pointer_or_array("abc");//<- erreur ici pour cause d'ambiguïté
    	char const *abc = "abc";
    	pointer_or_array(abc);
    	return 0;
    ]
    J'aurais pourtant cru que les signatures étaient différentes et que les "string literal" étaient de type "character array" et non de type "character pointer".
    Comment donc résoudre cette ambiguïté ?
    Merci !

  2. #2
    Membre Expert
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Par défaut
    Bonjour, excellente question.

    Bien que "abc" soit une prvalue de type const char[4], les deux instantiations suivantes sont valides :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    template<> void pointer_or_array<char>(char const *rs)
    template<> void pointer_or_array<char, 4>(char const (&rs)[4])
    En effet, le decay du tableau en pointeur est considéré avant le choix du meilleur candidat. Les deux sont donc du même ordre.

    Afin de résoudre cette ambiguïté, je vous propose d'appeler une instantiation explicite de votre fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pointer_or_array<char, 4>("abc");

  3. #3
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Bonjour,

    Voici une solution qui n'oblige pas l'appelant à préciser explicitement les arguments de template :
    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
     
    #include <iostream>
    #include <type_traits>
     
    template<class T, std::enable_if_t<std::is_pointer_v<std::remove_reference_t<T>>, int> = 0>
    void pointer_or_array(T&& param)
    {
    	std::cout << std::forward<T>(param) << " size: ?" << std::endl;
    }
     
    template<class T, std::enable_if_t<std::is_array_v<std::remove_reference_t<T>>, int> = 0>
    void pointer_or_array(T&& param)
    {
    	std::cout << std::forward<T>(param) << " size: " << std::extent<std::remove_reference_t<T>>::value << std::endl;
    }
     
    int main()
    {
    	pointer_or_array("abc");
    	char const* abc = "abc";
    	pointer_or_array(abc);
    	return 0;
    }
    Vivement les concepts du C++20 ! Ces dernier permettront d'éviter les std::enable_if_t.

  4. #4
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Pyramidev, bravo

    Plus difficile maintenant, j'aimerais surcharger l'operator+() de basic_string pour lui ajouter le cas du paramètre array:
    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
    template<class Chr, class Tr, class Al, size_t Rswz>
    inline basic_string<Chr, Tr, Al> operator+(
    	basic_string<Chr, Tr, Al> const & ls,
    	Chr const (&rs)[Rswz])
    {
    	basic_string<Chr, Tr, Al> s;
    	s.reserve(ls.size() + Rswz - 1);
    	return s.append(ls).append(rs, Rswz - 1);
    }
     
    template<class Chr, class Tr, class Al, size_t Rswz>
    inline basic_string<Chr, Tr, Al> operator+(
    	basic_string<Chr, Tr, Al> && ls,
    	Chr const (&rs)[Rswz])
    {
    	return std::move(ls.append(rs, Rswz - 1));
    }
    Malheureusement le truc du enable_if is_pointer ne fonctionnera peut-être pas s'il n'est pas prévu par ceux qui ont écrit les sources de la STL...

    C'est le WE, j'y réflérirais la semaine prochaine

    Merci à tous et bon wékenne

  5. #5
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Bonjour en ce joli samedi,
    La nuit a porté conseil et m'apporté ceci
    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
    template<class T, std::enable_if_t<std::is_pointer_v<T>, int> = 0>
    void pointer_or_array(T param)
    {
    	std::cout << param << " size: ?" << std::endl;
    }
     
    template<class T, size_t S>
    void pointer_or_array(T const (&param)[S])
    {
    	std::cout << param << " size: " << S << std::endl;
    }
     
    int main()
    {
    	pointer_or_array("abc");
    	char const *abc = "abc";
    	pointer_or_array(abc);
    	return 0;
    ]
    Le code est plus simple et plus lisible, et aussi plus performant.
    Ici le pointeur est passé par valeur, tel quel. Dans le code de Pyramidev il est passé par référence (pour peu que j'ai bien pu juger le code en Release et optmisé de Visual Studio 2017).

  6. #6
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Aussi dans le code de pyramidev, si la fonction prend une rvalue reference en paramètre, cela ne change-t-il pas son contrat? (notamment dans le cas du pointeur, il pourrait être changé par la fonction)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Fonction qui retourne une collection
    Par superfly dans le forum Oracle
    Réponses: 9
    Dernier message: 25/06/2009, 18h02
  2. Fonction qui execute une opération mathematique
    Par durnambule dans le forum MS SQL Server
    Réponses: 8
    Dernier message: 24/04/2007, 17h42
  3. Fonction qui change une variable
    Par Taz_8626 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 30/03/2006, 12h54
  4. Réponses: 15
    Dernier message: 26/03/2006, 12h10
  5. Réponses: 5
    Dernier message: 18/10/2005, 21h53

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