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 :

Constructeur modèle sans argument, comment l’appeler ?


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé Avatar de nowahn
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 84
    Par défaut Constructeur modèle sans argument, comment l’appeler ?
    Bonjour,

    Premièrement, j’utilise le compilateur gcc/g++ version 4.5.0 sur Linux.

    En explorant le monde merveilleux des modèles (template), je suis tombé sur un os :
    on peut définir des fonctions modèles sans arguments (de fonction) et les appeler comme ceci :

    Code C++ : 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
    // Déclaration
    template<typename _Type>
    void Function();
     
    // Définition
    template<typename _Type>
    void Function()
    {
       std::cout << "void Function<_Type>()\n";
    }
     
    // Instanciation explicite
    template
    void Function<int>();
     
    // Appel
    int main()
    {
       Function<int>();
       return 0;
    }

    Par contre, j’ai remarqué qu’on pouvait déclarer, définir et instancier explicitement des constructeurs modèles sans arguments (de fonction) de la même manière, mais je suis incapable de les appeler :

    Code C++ : 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    // Définition d’une classe
    class TClass
    {
    public:
       template<typename _Type>
       TClass();
    };
     
    // Définition du constructeur modèle
    template<typename _Type>
    TClass::TClass()
    {
       std::cout << "TClass::TClass<_Type>()\n";
    }
     
    // Instanciation explicite
    template
    TClass::TClass<int>(); // Ceci est légal
     
    // Utilisation
    int main()
    {
       TClass Class1; // Illégal, le constructeur par défaut n’est pas généré à
                      // cause de la présence du constructeur modèle (ça me semble
                      // normal)
     
       TClass Class2<int>; // Illégal, le '<' est pris pour un opérateur
                           // 'inférieur à'
     
       TClass Class3(TClass()); // Légal, le constructeur par copie par défaut est
                                // utilisé, ce qui me semble normal, mais le
                                // constructeur par défaut est généré ici alors
                                // qu’il ne l’est pas pour Class1, bizarre !!!
     
       TClass Class4(TClass<int>()); // Illégal, 'TClass<int>' est pris pour le
                                     // nom d’une classe modèle
     
       TClass Class5(TClass::TClass<int>()); // Illégal, un constructeur ne peut
                                             // pas être appelé directement
     
       return 0;
    }

    Pour info, voici les messages d’erreur renvoyés par g++ :
    Pour Class1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Test.cpp:25:11: error: no matching function for call to ‘TClass::TClass()’
    Test.cpp:5:1: note: candidate is: TClass::TClass(const TClass&)
    Pour Class2 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Test.cpp:29:17: error: expected initializer before ‘<’ token
    Pour Class4 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Test.cpp:37:18: error: ‘TClass’ is not a template
    Pour Class5 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Test.cpp:40:38: error: cannot call constructor ‘TClass::TClass’ directly
    Test.cpp:40:38: error:   for a function-style cast, remove the redundant ‘::TClass’
    Test.cpp:40:38: error: no matching function for call to ‘TClass::TClass()’
    Test.cpp:5:1: note: candidate is: TClass::TClass(const TClass&)
    Notez que :
    • J’ai essayer de ne laisser qu’une seule de ces 5 déclarations à la fois et j’ai bien les mêmes messages d’erreur.
    • Lorsque je ne laisse que Class3, que je compile et que j’exécute, c’est bien le constructeur généré par défaut que s’exécute, pas le constructeur modèle avec un paramètre quelconque (pas de sortie sur la sortie standard).
    • Lorsque je mets la déclaration de Class1 après celle de Class3, le constructeur par défaut n’est toujours pas généré pour Class1.
    • J’ai bien compris quelques subtilités des modèles, comme le besoin du mot clé template dans certains cas pour appeler une fonction modèle sans arguments (de fonction), du genre de ce qui est expliqué sur la FAQ de comeau.
      J’ai donc essayé de rajouter ce mot clé à différents endroits, mais rien n’est légal.


    Bref, je dois passer à côté de quelque chose, car il me semble bizarre qu’on puisse déclarer, définir et instancier explicitement une fonction modèle qu’on ne peut pas appeler.

    1. Quelqu’un sait comment appeler ce constructeur modèle ?
    2. Est-ce que le comportement de g++ est conforme à la norme ?
    3. Est-ce que d’autre compilateurs acceptent une de ces syntaxes d’appel (je n’en ai pas sous la main) ?
    4. Est-ce que la génération du constructeur par défaut dans un cas et pas dans l’autre (Class1 et Class3) est correct ou est-ce un bug de g++ ?


    PS : ceci est une question purement technique, je n’ai pas d’exemple d’utilisation pratique en vue, c’est par pure curiosité que je la pose.

  2. #2
    Membre émérite Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Par défaut
    Hello !
    J'avoue que je suis aussi perplexe…
    Reste à voir si l'on peut trouver des cas d'application…

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    <tout le blabla d'avant>

    En fait, il n'y a, tout simplement, aucune raison de vouloir créer un constructeur template si c'est pour ne pas utiliser le l'argument template en question

    Je m'explique:

    Le constructeur a pour but... de créer une instance "correctement initialisée" de ta classe.

    Si toute ta classe est déclarée template, il est "normal" que le constructeur s'adapte en fonction de l'argument template (ne serait ce parce qu'il est fort possible que le type soit utilisé par ailleurs )

    De même, il est "cohérent", si tu veux passer un (des) argument(s) au constructeur, de faire en sorte qu'ils s'adaptent à un maximum de types.

    Mais si c'est pour avoir le constrcteur... par défaut, quelle serait l'utilité
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Invité
    Invité(e)
    Par défaut
    Pour pouvoir passer le type aux constructeur peut-être. Un peu comme on pourrait avoir une classe qui à un type asssocie un gestionnaire, du genre :

    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
     
    class MaClasse
    {
             std::pair< std::type_info*, std::function<void()> > maPaire;
    public:
             template<class T>
             MaClasse(std::function<void()> maFonction)
             :maPaire( &typeid(T), maFonction )
             {}
     
             // Avec des fonctions membre de ce genre:
     
             template<class T>
             bool estAttachéACeType() const
             {
                     return (*maPaire.first) == typeid(T);
             }
    };
    Enfin c'est quand meme moins **problématique** que l'impossibilité de créer des version templates spécialisé de fonction (in peut d'ailleurs résoudre les deux problèmes de la même manière, avec une structure du genre Type2Type). Une limitation réelle des template que je trouve beaucoup plus contraignante, c'est l'impossibilité de les marier avec les fonctions virtuelles...

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Si ce n'est que là, tu passe, effectivement, un paramètre templatisé à ton constructeur, et ca, c'est tout à fait légal...

    une classe proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MaClass
    {
        public:
            template<typename iterator>
            MaClass(iterator b, iterator e):tab(b,e){}
            MaClass():tab(){}
        private:
            std::vector<int> tab;
    };
    fonctionne parfaitement, et pourra être utilisé en transmettant un écart compris entre deux itérateurs compatible (excluant std::map, en quelque sortes )

    Tu profitera d'ailleurs même de la déduction automatique des types

    Mais ce que nowahn essaye de faire, c'est de templatiser... le constructeur ne prenant pas d'argument, ce qui n'a strictement aucun sens: que veux tu spécialiser en terme de type au niveau du constructeur, si ce ne sont pas les arguments qui seront transmis
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Invité
    Invité(e)
    Par défaut
    Sans vouloir te contredire, dans mon exemple (qui est invalide), le constructeur ne prend justement pas de paramètre pouvant permettre de determiner le type de T. Par contre je suis d'accord que c'est vraiment chercher la petite bête...

Discussions similaires

  1. applet et constructeur sans argument
    Par new_wave dans le forum Applets
    Réponses: 2
    Dernier message: 09/05/2012, 08h58
  2. Pas de compilation sans constructeur sans argument!
    Par bertry dans le forum Débuter
    Réponses: 3
    Dernier message: 28/12/2011, 11h33
  3. Tableau et constructeurs sans arguments
    Par wafiwafi dans le forum Langage
    Réponses: 41
    Dernier message: 03/01/2010, 18h40
  4. [XSLT] - Modèle réutilisable... mais comment l'utiliser.
    Par jacquesh dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 17/02/2006, 11h07
  5. Signature d'une fonction sans argument
    Par cj227854 dans le forum C++
    Réponses: 5
    Dernier message: 20/10/2005, 17h01

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