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 :

Problème de conception avec les templates


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Décembre 2012
    Messages : 23
    Points : 13
    Points
    13
    Par défaut Problème de conception avec les templates
    Bonjour,

    Je cherche à définir un objet sous la forme d'un template. Je me heurte actuellement à un petit problème de conception. Je souhaite que ce template puisse prendre en paramètre des types primitifs, mais aussi des pointeurs.
    Les pointeurs sur les objets sont alloués à l'extérieur du template puis passés en paramètre. La classe template à la responsabilité de détruire ses objets.

    Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    template<typename T>
    class Test
    {
        private:
            T data;
            ...
     
        public:
            Test(const T& data){...};
            virtual ~Test(){delete this->data;} // pas cool crash si T est un type primitif.
            ....
    };
    La solution que j'ai trouvé (pas encore testé mais je suppose qu'elle fonctionne) est de spécialiser le template Test pour les types pointeurs alloués dynamiquements :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    template<typename T>
    class Test<T*>
    {
        private:
            T* data;
            ...
     
        public:
            Test(T* data){...};
            virtual ~Test(){delete this->data;}
            ....
    };
    Existe - t - il une méthode plus élégante et plus simple ?
    Merci

  2. #2
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

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

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ~Test() { this->delete_if_pointer(this->data); }
     
    template<class U> static void delete_if_pointer(U * p) { delete p; }
    template<class U> static void delete_if_pointer(U &) { }

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Décembre 2012
    Messages : 23
    Points : 13
    Points
    13
    Par défaut
    Merci pour la réponse.

    J'avais déjà essayer de réaliser cette proposition sans succès. J'ai retenté et cela ne fonctionne que si delete_if_pointers n'est pas une méthode d'instance..

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    A part en spécialisant ta classe pour les pointeurs, tu auras assez bien de mal à faire ce que tu veux, en effet. Cependant, je dois t'avouer que, conceptuellement, ton idée me choque au plus haut point...

    Car, soit ta classe se contente d'utiliser un pointeur (quelle qu'en soit l'origine) sur une ressource sur laquelle elle n'a aucun droit (et surtout pas celui de libérer la mémoire allouée à la ressource), soit, c'est à ta classe de s'occuper de tout : allocation dynamique de la mémoire à la création et libération lorsque la ressource n'est plus nécessaire (renseigne toi sur l'idiome nommé RAII ).
    Toute tentative de faire autrement ne pourrait que t'amener à des problèmes sans nom! Allez, un petit exemple pour te montrer ce que je veux dire :
    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
     
    template <typename T>
    class Test{
    public:
        Test(T const & t):value{t}{}
        /* le reste ... laissons juste le compilateur fournir le destructeur normal*/
    private:
        T value;
    };
    template <typename T>
    class Test<T*>{
    public:
        Test(T * pt):ptr{pt}{}
        ~Test(){
            delete ptr;
        }
    private:
       T * ptr;
    };
    int main(){
        int i;
        {
            Test<int> t(&i); // !!!! utilise la version avec un pointeur...
        } // t est détruit Test<int *>::~Test() est appelé -->
           // delete est appelé sur ptr MAIS... ptr n'est pas un pointeur
           // dont la valeur est définir par new ==> CRASH
        return 0;
    };
    Et encore, là, je te présente le cas le plus simple... Imagine si tu ne prend pas en compte le fait que la mémoire allouée à un pointeur (dont l'adresse est effectivement définie grâce à l'appel à new) a déjà été libérée (au travers de ta classe Test) et que tu essayes malgré tout de déréférencer ton pointeur... Que crois tu qu'il va arriver, selon toi

    Le fait est que mon exemple est simple et te permet de prendre conscience du problème, mais que tu risque d'avoir énormément de mal à garantir le fait qu'aucun chemin d'exécution n'aura eu pour effet d'invalider un pointeur représentant une adresse mémoire allouée grâce à new.
    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

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Décembre 2012
    Messages : 23
    Points : 13
    Points
    13
    Par défaut
    A part en spécialisant ta classe pour les pointeurs, tu auras assez bien de mal à faire ce que tu veux, en effet. Cependant, je dois t'avouer que, conceptuellement, ton idée me choque au plus haut point...
    En fait, RAII repose sur l'encapsulation strict des données non ?

    Ce qui me saoule c'est de devoir allouer à chaque fois que je passe un truc au constructeur. new dans tous les sens ne rique-t-il pas de me bouffer du temps sur des objets volumineux ?

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Décembre 2012
    Messages : 23
    Points : 13
    Points
    13
    Par défaut
    Citation Envoyé par Papipone Voir le message
    En fait, RAII repose sur l'encapsulation strict des données non ?

    Ce qui me saoule c'est de devoir allouer à chaque fois que je passe un truc au constructeur. new dans tous les sens ne rique-t-il pas de me bouffer du temps sur des objets volumineux ?
    Edit:

    Je vois trois solutions pour que le code soit plus safe (il en existe probablement d'autres) :
    • Allouer dans le constructeur et detruire dans le destructeur
    • Utiliser une factory pour manager les allocations
    • Utiliser des smart-pointers

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Papipone Voir le message
    Edit:

    Je vois trois solutions pour que le code soit plus safe (il en existe probablement d'autres) :
    1. Allouer dans le constructeur et detruire dans le destructeur
    2. Utiliser une factory pour manager les allocations
    3. Utiliser des smart-pointers
    (1) C'est le principe du RAII, en n'oubliant pas -- si tu choisi cette option -- d'appliquer la règle des cinq grands (hé oui, avant trois étaient suffisants, mais, depuis C++11, il y a aussi la construction de copie et l'affectation par déplacement à prendre en compte )
    (2) La factory n'a absolument rien à voir ici... Le principe de la fabrique est uniquement de permettre d'obtenir un (pointeur sur un) objet "passant pour être du type de base" alors qu'il est d'un type dérivé, tout en évitant à l'utilisateur de la factory d'avoir à s'inquiéter du type réel de l'objet créé
    (3) c'est encore la meilleure solution, mais en restant dans l'idée d'allouer la ressource sous-jacente à l'intérieur de la classe, et non en transmettant un pointeur (qu'il soit intelligent ou non) sur cette ressource au constructeur
    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

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Papipone Voir le message
    En fait, RAII repose sur l'encapsulation strict des données non ?
    RAII repose surtout sur le fait que la création d'une donnée d'un type particulier doit veiller à allouer les ressources nécessaires à cette donnée, et sur le fait (bien plus important encore) que la destruction de la donnée provoquera la libération des ressources en question.

    Le simple fait de passer un pointeur (qu'il soit intelligent ou non) à ta classe pour qu'elle s'occupe, lorsque l'instance est détruite, de la libération de la mémoire allouée à ce pointeur brise le RAII . Du moins, tel est le cas dans ta situation, et tel est le cas de manière générale : la seule exception étant l'utilisation d'une fabrique qui fournit un pointeur (intelligent ou non) à la classe qui devra veiller à maintenir la ressource "tant qu'elle est nécessaire"

    Ce qui me saoule c'est de devoir allouer à chaque fois que je passe un truc au constructeur. new dans tous les sens ne rique-t-il pas de me bouffer du temps sur des objets volumineux ?
    C'est bien pour cela que, si new il y a, il ne doit y en avoir qu'à un seul endroit: au niveau du constructeur de ta classe template

    Et encore, l'idéal serait de passer par un pointeur intelligent, si bien que je viens de penser à une manière assez souple pour faire ce que tu veux... Observe la technique
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
     
    /* deux "tags" : le premier représente le fait que l'on veut un pointeur, le deuxième représente le fait qu'on veut une valeur */
    struct PointerTag{};
    struct ValueTag{};
    /* un trait permettant de définir le type de la donnée interne */
    template <typename T, typename TAG>
    struct TestTrait{
        using ValueType = T;
    };
    /* et sa spécialisation pour le cas où l'on veut un pointeur */
    template <typename T>
    struct TestTrait<T, PointerTag>{
        using ValueType = std::unique_ptr<T>;
    };
    /* une structure qui défini la manière de créer l'objet */
    template <typename T, typename TAG>
    struct ValueConstructor{
        T operator()(T v){
            return v;
        }
    };
    /* la même structure mais spécialisée pour représenter un pointeur */
    template <typename T>
    struct ValueConstructor<T, PointerTag>{
        using ValueType = typename TestTrait<T,PointerTag>::ValueType;
        ValueType operator()(T v){
            return std::make_unique<T>(v);
        }
    };
    template <typename T, typename TAG = ValueTag>
    class Test{
        /* un alias de type représentant le type de la donnée sous-jacente
         * ce sera soit une donnée "normale", soit un pointeur intelligent
         * en fonction du paramètre transmis à TAG
         */
        using ValueType = typename TestTrait<T, TAG>::ValueType;
        /* un alias de type sur le foncteur qui créera la donnée sous-jacente
          */
        using Ctor = ValueConstructor<T, TAG>;
    public:
        /* constructeur spécifiquement utilisé si on utilise la donnée et non le pointeur
         * "il n'y a qu'à" initialiser la donnée
         */
        template <typename  U= TAG>
        Test(T v, typename std::enable_if<std::is_same<U, ValueTag>::value>::type * =nullptr):value_(Ctor()(v)){
        }
        /* constructeur spécifiquement utilisé si on veut utiliser un pointeur
         * La copie d'un std::unique_ptr étant désactivée, il faut utiliser la sémantique de déplacement
         */
        template <typename  U= TAG>
        Test(T v, typename std::enable_if<std::is_same<U, PointerTag>::value>::type * =nullptr):value_(std::move(Ctor()(v))){
        }
        template <typename  U= TAG>
        T value( typename std::enable_if<std::is_same<U, ValueTag>::value>::type * =nullptr) const{
            return value_;
        }
        template <typename  U= TAG>
        T value( typename std::enable_if<std::is_same<U, PointerTag>::value>::type * =nullptr) const{
            return *(value_.get());
        }
    private:
        /* la donnée sous-jacente... une donnée "normale" si TAG = ValueTag,
         * un pointeur intelligent si TAG = PointerTag
         */
        ValueType value_;
    };
    /* le tout sera utilisé sous la forme de */
    int main(){
        Test<int> value(5); // la donnée sous-jacente est une donnée "classique"
        Test<int, PointerTag> ptr(10); // la donnée sous-jacente est un pointeur
        std::cout<<"value.value() == "<<value.value() <<"\n"
                      <<"ptr.value() == "<<ptr.value() <<"\n";
        return 0;
    }
    NOTA: l'utilisation de std::enable_if nécessite l'inclusion du fichier d'en-tête <type_traits> et celle d'un unique_ptr nécessite l'inclusion du fichier d'en-tête <memory> (ces deux fonctionnalités nécessitent un compilateur supportant au minimum C++11). Enfin, std::make_unique n'est apparu qu'en C++14, peut de changements seraient nécessaires pour rendre ce code compilable en C++11
    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

  9. #9
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Décembre 2012
    Messages : 23
    Points : 13
    Points
    13
    Par défaut
    Merci pour les réponses.

    D'après ce que j'ai vu, RAII s'appuie sur des mécanismes de sécurité permettant surtout de prévenir les fuites mémoires via des techniques de management des exceptions et autres trucs subtiles et encore un peu obscure pour moi (pour l'instant, ).

    (2) La factory n'a absolument rien à voir ici... Le principe de la fabrique est uniquement de permettre d'obtenir un (pointeur sur un) objet "passant pour être du type de base" alors qu'il est d'un type dérivé, tout en évitant à l'utilisateur de la factory d'avoir à s'inquiéter du type réel de l'objet créé
    J'étais en train de chercher sur le net et je suis tombé la dessus : http://www.codeproject.com/Articles/...Factories-in-C
    La personne utilise une factory qui permet entre autre de manager les pointeurs d'une classe sans pour autant avoir besoin de delete son objet principal (ils sont détruits lorsque la factory sort du scope d'un bloc de code). Enfin bon, je pense pas que cela me soit d'une grande utilité car la durée de vie de mes données allouées dynamiquement doit être égale à celle du programme, à peu de chose près.

    L'usage des smart-pointers semble compromis étant donné que Qt n'en n'est pas fan (Il me semble, j'avais testé il y a un moment et ça crashé bien comme il faut lors de la destruction d'objets dérivés de QObject).

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par Papipone Voir le message
    L'usage des smart-pointers semble compromis étant donné que Qt n'en n'est pas fan (Il me semble, j'avais testé il y a un moment et ça crashé bien comme il faut lors de la destruction d'objets dérivés de QObject).
    Qt pas fan des pointeurs intelligents Va raconter cela à un cheval de bois, et tu auras une ruade en prime!!! Toute la mécanique interne des widgets de Qt est pour ainsi dire basée sur les pointeurs intelligents... C'est pour cette raison que tu fais systématiquement un new dans le construteur sans jamais faire de delete dans le destructeur !

    Simplement, Qt a eu le bon gout de faire de l'utilisation des pointeurs intelligents un "détail d'implémentation" qui ne ressort que très rarement

    De plus, il faut voir à quoi va servir ta classe, mais, dans l'optique où il est conseillé d'éviter de polluer tes fonctionnalités métier avec des fonctionnalités issues de Qt, si ta conception est bonne, tu n'auras jamais le moindre problème

    EDIT quant au lien que tu as donné, le type n'a visiblement pas compris le principe du patron de conception Factory... Ce n'est absolument pas à la fabrique de maintenir les objets qu'elle a créé en mémoire, car cela contrevient au SRP (Single Responsability Principle ou principe de la responsabilité unique)

    C'est un peu comme si tu décidais de te mettre à construire des voitures, mais que tu refusais obstinément de les vendre, et que tu n'accepterais que de les prêter, cela n'aurait absolument pas de sens . Non, une fabrique crée quelque chose, puis elle le fournit à "quelqu'un ou quelque chose" qui en devient le "propriétaire légitime" (et qui a le droit de décider du moment où l'élément créé est "bon pour la casse", voire, de décider de le céder à quelqu'un d'autre qui ne deviendra alors le "nouveau" propriétaire légitime )
    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

  11. #11
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Décembre 2012
    Messages : 23
    Points : 13
    Points
    13
    Par défaut
    Bonjour,

    Merci, pour toutes ces précisions.

    cela contrevient au SRP (Single Responsability Principle ou principe de la responsabilité unique)
    Il va bien falloir que je mette ça dans la tête bien profond car il m'arrive bien souvent de coder, passez moi l'expression, avec le cul.

    Du coup, j'ai retapé la classe de test sans pointeurs intelligents (un compilateur pour architecture spécifique ne me le permet pas ).
    Voila ce que cela donne :

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
     
    #ifndef NODE_HPP
    #define NODE_HPP
     
    #include <cstdlib>
    #include <iostream>
     
    #include "AbstractBinaryNode.hpp"
     
    template<typename T>
    class BinaryNode;
     
    template<typename T>
    std::ostream& operator <<(std::ostream&, BinaryNode<T> const*);
     
    template<typename T>
    struct NodeTrait
    {
        using value_type = T;
    };
     
    template<typename T>
    struct NodeTrait<T*>
    {
        using value_type = T*;
    };
     
    template<typename T>
    struct NodeValueAllocator
    {
        T operator()(const T& value)
        {
            return value;
        }
    };
     
    template<typename T>
    struct NodeValueAllocator<T*>
    {
        using value_type = typename NodeTrait<T*>::value_type;
        value_type operator()(const T* value)
        {
            return new T(*value);
        }
    };
     
    template<typename T>
    struct NodeDestructor
    {
        void operator()(T value){}
    };
     
    template<typename T>
    struct NodeDestructor<T*>
    {
        void operator()(T* value)
        {
            delete value;
        }
    };
     
    template<typename T>
    class BinaryNode : public AbstractBinaryNode<T>
    {   
            using value_type = typename NodeTrait<T>::value_type;
            using c_tor = NodeValueAllocator<T>;
            using d_tor = NodeDestructor<T>;
     
        protected:
            value_type value;
     
            BinaryNode<value_type>* parent;
            BinaryNode<value_type>* left;
            BinaryNode<value_type>* right;
     
        public:
            BinaryNode();
            BinaryNode(T data);
            BinaryNode(T data, BinaryNode<T>* parent);
            BinaryNode(T data, BinaryNode<T>* parent, 
                              BinaryNode<T>* left, BinaryNode<T>* right);
            BinaryNode(const BinaryNode<T>* node);
            virtual ~BinaryNode();
     
            T getData();
            T getParentData();
            T getLeftData();
            T getRightData();
     
            void setData(T data);
            void setParentData(T data);
            void setLeftData(T data);
            void setRightData(T data);
     
            virtual BinaryNode<T>* clone();
     
            bool operator ==(const BinaryNode<T>* node);
     
            friend std::ostream& operator << <>(std::ostream& stream, const BinaryNode<T>* node);
    };
     
    #include "../src/BinaryNode.cpp"
    #endif /* BINARYNODE_HPP */
    Cela vous parait-il correcte ?
    Merci

Discussions similaires

  1. Problème de généricité avec les templates
    Par sfarc dans le forum Débuter
    Réponses: 9
    Dernier message: 30/12/2013, 03h51
  2. Problème de conception avec les mutex de Boost
    Par Benoit_T dans le forum Threads & Processus
    Réponses: 1
    Dernier message: 22/03/2012, 17h15
  3. Problème avec les templates de class
    Par _SamSoft_ dans le forum C++
    Réponses: 8
    Dernier message: 21/08/2008, 10h30
  4. Problème avec les templates
    Par F-fisher dans le forum C++
    Réponses: 7
    Dernier message: 28/06/2008, 16h04
  5. Réponses: 5
    Dernier message: 04/03/2007, 15h33

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