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 :

Réorganisation de code : fichier .cpp, .h et .inl.


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut Réorganisation de code : fichier .cpp, .h et .inl.
    Salut,

    je voudrais réorganiser le code source de mon moteur car j'ai des fichiers.h avec des fonctions template et non template, bref, c'est un peu le bazard alors j'ai essyer de séparer ça dans 3 fichiers (le 1er ne contenant que les prototypes des fonctions template et non template, le second contenant la définition des fonctions template et le dernier contenant la définition des fonctions non templates, voici ce que ça donne :

    mon fichier .h :

    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
    104
    105
    106
    107
     
    #ifndef ODFAEG_ACTION_MAP_HPP
    #define ODFAEG_ACTION_MAP_HPP
    #include "action.h"
    /**
      *\namespace odfaeg
      * the namespace of the Opensource Development Framework Adapted for Every Games.
      */
    namespace odfaeg
    {
     
    /**
    * \file actionMap.h
    * \class ActionMap
    * \brief Store one action, a member function pointer and sf::Events.
    * \author Duroisin.L
    * \version 1.0
    * \date 1/02/2014
    * Store one or more triggered SFML Events and an ACTION.
    * Link the action to a pointer to a member function. (who's called when the action is triggered on an object)
    */
     
    class ODFAEG_CORE_API ActionMap
    {
    friend class Action;
    public :
        /** \fn ActionMap(Action action, FastDelegate<void> delegate)
        *  \brief Constructor :Construct an action map and link it to a member function, an action and an object
        of the class of the member function
        *  \param action : the action on which we want to bind the function.
        *  \param FastDelegate<void> the function to invoke throw the delegate when the action of the actionmap is triggered.
        */
        ActionMap (Action action, FastDelegate<void> delegate);
        /** \fn ActionMap(Action action, FastDelegate trigger, FastDelegate<void> command)
        *  \brief Constructor :Construct an action map and link it to a member function, an action and an object
        of the class of the member function
        *  \param action : the action on which we want to bind the function.
        *  \param FastDelegate<bool> : the function to invoke to test if the action is triggered.
        *  \param FastDelegate<void> the function to invoke throw the delegate when the action of the actionmap is triggered.
        */
        ActionMap (Action action, FastDelegate<bool> trigger, FastDelegate<void> command);
        /**\fn containsEvent (sf::Event &event)
        *  \brief check if the sf::Event is in the action map.
        *  \param the sf::Event to check in.
        *  \return true if the sf::Event is in the action map, false otherwise.
        */
        bool containsEvent (sf::Event &event);
        /** \fn bool isTriggered()
        *   \brief return true if the actionMap is triggered.
        *   \return true if the actionMap is triggered, false otherwise.
        */
        bool isTriggered();
        /** \fn bool containsBufferEvent(sf::Event& event)
        *   \brief check if the sf::Event is contained in the event buffer of an action
        *   \param the sf::Event to check with.
        */
        bool containsBufferEvent(sf::Event& event);
        /** \fn void clear ()
        *   \brief clear all the sf::events who are stored.
        */
        static void clear ();
        /** \fn void pushEvent (sf::Event& event)
        *   \brief store all the incoming sf::events which are triggered.
        *   \param the triggered sf::Event.
        */
        static void pushEvent (sf::Event& event);
        /** \fn void getEvents()
        *   \brief return all sfml events which are generated since the last event loop.
        *   \return the sfml event which are generated since the last loop.
        */
        static std::vector<sf::Event> getEvents();
        /** \fn void setParams(O* object, A... args)
        *   \brief change params of a command.
        *   \param O* object : the object of the actionmap's member function to call the function on.
        *   \param A... args : the arguments of the actionmap's member function to pass when the function is called.
        */
        template<typename O, typename ...A> void setParams(O* object, A... args);
        /** \fn void operator()()
        *   \brief call the member function linked to the action map and clear all the SFML events which are generated.
        */
        void operator()();
        /**\fn
        /* \brief remove an sf::Event from the stack.
        *  \param sf::Event event : the sfml event to remove from the stack.
        */
        static void removeEvent(sf::Event& event);
    private :
     
        /** \fn bool equalEvent (sf::Event event, sf::Event other)
        *   \brief test if two events are equal.
        *   \param sf::Event event : the event.
        *   \param sf::Event other : the otherevent.
        *   \return return true if the two events are equal.
        */
        static bool equalEvent (sf::Event& event, sf::Event& other);
        /** < the action mapped to the command.*/
        Action *action;
        /** < the function mapped to the command.*/
        FastDelegate<void> *delegate;
        /** < the trigger mapped to the command.*/
        FastDelegate<bool> *trigger;
        /** < the SFML events generated.*/
        static std::vector<sf::Event> events;
    };
    //#include "actionMap.inl"
    }
    #endif // ACTION_MAP
    mon fichier .inl

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    /** \fn void setParams(O* object, A... args)
    *   \brief change params of a command.
    *   \param O* object : the object of the actionmap's member function to call the function on.
    *   \param A... args : the arguments of the actionmap's member function to pass when the function is called.
    */
    template<typename O, typename ...A> void ActionMap::setParams(O* object, A... args) {
        delegate->setParams(object, args...);
    }
    Et mon fichier .cpp

    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
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
     
    #include "../../../include/odfaeg/Core/actionMap.h"
    namespace odfaeg {
    std::vector<sf::Event> ActionMap::events = std::vector<sf::Event> ();
    /** \fn ActionMap(Action action, FastDelegate<void> delegate)
    *  \brief Constructor :Construct an action map and link it to a member function, an action and an object
    of the class of the member function
    *  \param action : the action on which we want to bind the function.
    *  \param FastDelegate<void> the function to invoke throw the delegate when the action of the actionmap is triggered.
    */
    ActionMap::ActionMap (Action action, FastDelegate<void> delegate)
    {
        this->action = new Action(action);
        this->delegate = new FastDelegate<void>(delegate);
        trigger = nullptr;
     
    }
    /** \fn ActionMap(Action action, FastDelegate trigger, FastDelegate<void> command)
    *  \brief Constructor :Construct an action map and link it to a member function, an action and an object
    of the class of the member function
    *  \param action : the action on which we want to bind the function.
    *  \param FastDelegate<bool> : the function to invoke to test if the action is triggered.
    *  \param FastDelegate<void> the function to invoke throw the delegate when the action of the actionmap is triggered.
    */
    ActionMap::ActionMap (Action action, FastDelegate<bool> trigger, FastDelegate<void> command) {
        this->action = new Action(action);
        this->delegate = new FastDelegate<void>(command);
        this->trigger = new FastDelegate<bool>(trigger);
    }
    /**\fn containsEvent (sf::Event &event)
    *  \brief check if the sf::Event is in the action map.
    *  \param the sf::Event to check in.
    *  \return true if the sf::Event is in the action map, false otherwise.
    */
    bool ActionMap::containsEvent (sf::Event &event)
    {
        std::vector<sf::Event>::iterator it;
        for (it = events.begin(); it != events.end(); it++)
        {
            if (equalEvent(event, *it))
                return true;
        }
        return false;
    }
    /** \fn bool isTriggered()
    *   \brief return true if the actionMap is triggered.
    *   \return true if the actionMap is triggered, false otherwise.
    */
    bool ActionMap::isTriggered()
    {
        if (trigger == nullptr && action->isTriggered())
        {
            action->clearEventsBuffers();
            return true;
        } else if ((*trigger)() && action->isTriggered()) {
            action->clearEventsBuffers();
            return true;
        }
        return false;
    }
    /** \fn bool containsBufferEvent(sf::Event& event)
    *   \brief check if the sf::Event is contained in the event buffer of an action
    *   \param the sf::Event to check with.
    */
    bool ActionMap::containsBufferEvent(sf::Event& event) {
        return action->containsEvent(event);
    }
    /** \fn void clear ()
    *   \brief clear all the sf::events who are stored.
    */
    void ActionMap::clear ()
    {
        events.clear();
    }
    /** \fn void pushEvent (sf::Event& event)
    *   \brief store all the incoming sf::events which are triggered.
    *   \param the triggered sf::Event.
    */
    void ActionMap::pushEvent (sf::Event& event)
    {
        std::vector<sf::Event>::iterator it;
        bool containsEvent = false;
        for (it = events.begin(); it != events.end(); it++)
        {
            if (equalEvent(event, *it))
                containsEvent = true;
        }
        if (!containsEvent)
            events.push_back(event);
    }
    /** \fn void getEvents()
    *   \brief return all sfml events which are generated since the last event loop.
    *   \return the sfml event which are generated since the last loop.
    */
    std::vector<sf::Event> ActionMap::getEvents()
    {
        return events;
    }
     
    /** \fn void operator()()
    *   \brief call the member function linked to the action map and clear all the SFML events which are generated.
    */
    void ActionMap::operator()()
    {
        (*delegate)();
        action->clearEventsBuffers();
    }
    /**\fn
    /* \brief remove an sf::Event from the stack.
    *  \param sf::Event event : the sfml event to remove from the stack.
    */
    void ActionMap::removeEvent(sf::Event& event) {
        std::vector<sf::Event>::iterator it;
        for (it = events.begin(); it != events.end();) {
            if (equalEvent(*it, event))
                it = events.erase(it);
            else
                it++;
        }
    }
    bool ActionMap::equalEvent (sf::Event& event, sf::Event& other) {
        if (event.type != other.type)
            return false;
        if (event.type == sf::Event::Resized)
        {
            return event.size.width == other.size.width && event.size.height == other.size.height;
        }
        if (event.type == sf::Event::TextEntered)
        {
            return event.text.unicode == other.text.unicode;
        }
        if (event.type == sf::Event::KeyPressed || event.type == sf::Event::KeyReleased)
        {
            return event.key.code == other.key.code;
        }
        if (event.type == sf::Event::MouseWheelMoved)
        {
            return event.mouseWheel.delta == other.mouseWheel.delta;
        }
        if (event.type == sf::Event::MouseButtonPressed || event.type == sf::Event::MouseButtonReleased)
        {
            return event.mouseButton.button == other.mouseButton.button;
        }
        if (event.type == sf::Event::MouseMoved)
        {
            return event.mouseMove.x == other.mouseMove.x && event.mouseMove.y == other.mouseMove.y;
        }
        if (event.type == sf::Event::JoystickButtonPressed || event.type == sf::Event::JoystickButtonReleased)
        {
            return event.joystickButton.joystickId == other.joystickButton.joystickId
                   && event.joystickButton.button == other.joystickButton.button;
        }
        if (event.type == sf::Event::JoystickMoved)
        {
            return event.joystickMove.joystickId == other.joystickMove.joystickId
                   && event.joystickMove.position == other.joystickMove.position;
        }
        return false;
    }
    }
    Seulement ça ne marche pas lorsque j'appelle la fonction setParams, j'ai une erreur de référence indéfinie.

    Comment faire ça correctement ?

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Ta fonction template n'est pas inline. Il est donc étrange de la mettre dans un fichier .inl.

    Pourquoi, dans ton .h, as-tu commenté l'inclusion de ton .inl ?

  3. #3
    Invité
    Invité(e)
    Par défaut
    Ha oui juste je dois la mettre inline, je vais devoir faire ça pour toutes les fonctions courte que j'utilise souvent d'ailleurs. (Et pas que les fonction template)

    Bref apparemment on peut pas séparer les fonctions templates on est obligé des les définir dans le .h, je l'ai donc inclus ici :

    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 ODFAEG_ACTION_MAP_HPP
    #define ODFAEG_ACTION_MAP_HPP
    #include "action.h"
    /**
      *\namespace odfaeg
      * the namespace of the Opensource Development Framework Adapted for Every Games.
      */
    namespace odfaeg
    {
     
    /**
    * \file actionMap.h
    * \class ActionMap
    * \brief Store one action, a member function pointer and sf::Events.
    * \author Duroisin.L
    * \version 1.0
    * \date 1/02/2014
    * Store one or more triggered SFML Events and an ACTION.
    * Link the action to a pointer to a member function. (who's called when the action is triggered on an object)
    */
     
    class ODFAEG_CORE_API ActionMap
    {
    friend class Action;
    public :
        /** \fn ActionMap(Action action, FastDelegate<void> delegate)
        *  \brief Constructor :Construct an action map and link it to a member function, an action and an object
        of the class of the member function
        *  \param action : the action on which we want to bind the function.
        *  \param FastDelegate<void> the function to invoke throw the delegate when the action of the actionmap is triggered.
        */
        ActionMap (Action action, FastDelegate<void> delegate);
        /** \fn ActionMap(Action action, FastDelegate trigger, FastDelegate<void> command)
        *  \brief Constructor :Construct an action map and link it to a member function, an action and an object
        of the class of the member function
        *  \param action : the action on which we want to bind the function.
        *  \param FastDelegate<bool> : the function to invoke to test if the action is triggered.
        *  \param FastDelegate<void> the function to invoke throw the delegate when the action of the actionmap is triggered.
        */
        ActionMap (Action action, FastDelegate<bool> trigger, FastDelegate<void> command);
        /**\fn containsEvent (sf::Event &event)
        *  \brief check if the sf::Event is in the action map.
        *  \param the sf::Event to check in.
        *  \return true if the sf::Event is in the action map, false otherwise.
        */
        bool containsEvent (sf::Event &event);
        /** \fn bool isTriggered()
        *   \brief return true if the actionMap is triggered.
        *   \return true if the actionMap is triggered, false otherwise.
        */
        bool isTriggered();
        /** \fn bool containsBufferEvent(sf::Event& event)
        *   \brief check if the sf::Event is contained in the event buffer of an action
        *   \param the sf::Event to check with.
        */
        bool containsBufferEvent(sf::Event& event);
        /** \fn void clear ()
        *   \brief clear all the sf::events who are stored.
        */
        static void clear ();
        /** \fn void pushEvent (sf::Event& event)
        *   \brief store all the incoming sf::events which are triggered.
        *   \param the triggered sf::Event.
        */
        static void pushEvent (sf::Event& event);
        /** \fn void getEvents()
        *   \brief return all sfml events which are generated since the last event loop.
        *   \return the sfml event which are generated since the last loop.
        */
        static std::vector<sf::Event> getEvents();
     
        /** \fn void operator()()
        *   \brief call the member function linked to the action map and clear all the SFML events which are generated.
        */
        void operator()();
        /**\fn
        /* \brief remove an sf::Event from the stack.
        *  \param sf::Event event : the sfml event to remove from the stack.
        */
        static void removeEvent(sf::Event& event);
        #include "actionMap.inl"
    private :
     
        /** \fn bool equalEvent (sf::Event event, sf::Event other)
        *   \brief test if two events are equal.
        *   \param sf::Event event : the event.
        *   \param sf::Event other : the otherevent.
        *   \return return true if the two events are equal.
        */
        static bool equalEvent (sf::Event& event, sf::Event& other);
        /** < the action mapped to the command.*/
        Action *action;
        /** < the function mapped to the command.*/
        FastDelegate<void> *delegate;
        /** < the trigger mapped to the command.*/
        FastDelegate<bool> *trigger;
        /** < the SFML events generated.*/
        static std::vector<sf::Event> events;
    };
     
    }
    #endif // ACTION_MAP
    Et là ça marche mais je sais pas si c'est la meilleur manière de faire. :X

    PS : sinon les fichier .inl sont les seuls qui sont coloré dans code::blocks...., j'ai essayer de mettre .tpp mais ça ne colore pas.

  4. #4
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par Lolilolight Voir le message
    Et là ça marche mais je sais pas si c'est la meilleur manière de faire. :X

    PS : sinon les fichier .inl sont les seuls qui sont coloré dans code::blocks...., j'ai essayer de mettre .tpp mais ça ne colore pas.
    Le code de ton premier post était la bonne façon de faire. Pour Code::Blocks, probablement une simple option de configuration.

    Niveau code, ça donne ça
    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
    //foo.h
    #pragma once
    struct Foo {
    	template <class T>
    	T bar() const;
     
    	int baz() const;
    };
    #include "foo.tpp"
     
    // foo.tpp
    template <class T>
    T Foo::bar() const {
    	return T();
    }
     
    // foo.cpp
    #include "foo.h"
     
    int Foo::baz() const {
    	return 42;
    }
    Citation Envoyé par oodini Voir le message
    Pourquoi, dans ton .h, as-tu commenté l'inclusion de ton .inl ?
    Je pense aussi que l'erreur vient de là.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Oui ma première méthode était la bonne j'avais juste oublié le ActionMap:: devant le nom de la fonction dans le fichier .tpp et, de décommenter cette ligne de code.

  6. #6
    Membre régulier
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Août 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2012
    Messages : 44
    Points : 91
    Points
    91
    Par défaut
    Je déteste les fichiers tpl, ou inl. A quoi bon creer ces fichiers alors que tu as besoins de les inclure de toute facon, soit quelque part discretement dans ton .h, soit explicitement dans tes cpp.

    Le corps des templates doit etre visible par tout ou ils sont utilises, mettons les a la fin des headers, tout le monde sera content.

    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
    // Fichier Foo.h
    #ifndef __FOO__H
    #define __FOO__H
     
    template <class T>
    class Foo {
        void faireCi();
     
        template <class U>
        void faireCa();
    }; // mon interface fini ici
     
    // la partie implementation, a ignorer pour les developpeurs qui utilisent la classe Foo
    template <class T>
    void Foo::faireCi() {
    // blah blah
    }
     
    template <class T, class U>
    void Foo::faireCa() {
    // blah blah
    }
    #endif // __FOO__H
    //Fin de fichier Foo.h

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Citation Envoyé par forrestdg Voir le message
    Je déteste les fichiers tpl, ou inl. A quoi bon créer ces fichiers alors que tu as besoins de les inclure de toute façon, soit quelque part discrètement dans ton .h, soit explicitement dans tes cpp.
    Cela sert à séparer la déclaration de l'implémentation.

    Citation Envoyé par forrestdg Voir le message
    Le corps des templates doit être visible par tout ou ils sont utilises, mettons les a la fin des headers, tout le monde sera content.
    Tout le monde sera également content si un include est mis à la fin des headers. Sauf les râleurs.

  8. #8
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Salut

    Perso j'en ai ras la casquette de séparer la déclaration de l'implémentation pour les templates, c'est lourdingue à écrire, en particulier lorsqu'on a des fonctions membres templates à l'intérieur d'une classe template, et au final tout le monde est inclus quand même dans les headers. Alors fuck the police, j'écris le code in-class directement pour les templates. Ca n'empêche même pas l'externalisation de fonctionner. Je suis plus productif ainsi et si quelqu'un veut lire l'interface épurée du code, il n'a qu'à passer un coup de Doxygen dessus ou de folding dans vim.

    Eventuellement, peut-être qu'une inclusion conditionnelle de l'implémentation lors d'un cas d'externalisation pourrait accélérer la compilation, mais je n'en suis même pas sûr et c'est en tout cas quelque chose que j'ai encore jamais vu faire.

    De toute façon en C++, en terme de conventions de nommage des fichiers, c'est complètement la foire entre les *.hpp, *.tpp, *.cc, *.cpp, *.C, *.cxx. L'important c'est de choisir une convention pour le projet et de s'y tenir.
    Find me on github

  9. #9
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 705
    Points
    2 705
    Par défaut
    Disons que je trouve ça étrange de présenter de manière aussi agressive et péremptoire ce qui relève des préférences personnelles.

  10. #10
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    Salut

    Perso j'en ai ras la casquette de séparer la déclaration de l'implémentation pour les templates, c'est lourdingue à écrire, en particulier lorsqu'on a des fonctions membres templates à l'intérieur d'une classe template, et au final tout le monde est inclus quand même dans les headers. Alors fuck the police, j'écris le code in-class directement pour les templates. Ca n'empêche même pas l'externalisation de fonctionner. Je suis plus productif ainsi et si quelqu'un veut lire l'interface épurée du code, il n'a qu'à passer un coup de Doxygen dessus ou de folding dans vim.

    Eventuellement, peut-être qu'une inclusion conditionnelle de l'implémentation lors d'un cas d'externalisation pourrait accélérer la compilation, mais je n'en suis même pas sûr et c'est en tout cas quelque chose que j'ai encore jamais vu faire.

    De toute façon en C++, en terme de conventions de nommage des fichiers, c'est complètement la foire entre les *.hpp, *.tpp, *.cc, *.cpp, *.C, *.cxx. L'important c'est de choisir une convention pour le projet et de s'y tenir.
    Pareil, pour les template je met ça directement dans la classe, et pareil pour les fonctions courtes non template (1 ou 2 lignes max).

    Mais c'est pas forcément une bonne chose, spour ça que je recommande de séparer. Après que ça soit séparer ou pas, tant que c'est tout le temps pareil, pas de problème (comme les tabulations vs espaces pour l'indentation, les deux sont valides, et chacun à ses préférences la dessus).

    Citation Envoyé par jblecanard Voir le message
    Je suis plus productif ainsi et si quelqu'un veut lire l'interface épurée du code, il n'a qu'à passer un coup de Doxygen dessus ou de folding dans vim.
    C'est le principal problème oui, on à pas l'interface épurée directement dispo, mais tous les IDE fournissent cette vue, c'est juste dommage de devoir dépendre d'un IDE.

  11. #11
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    C'est le principal problème oui, on à pas l'interface épurée directement dispo, mais tous les IDE fournissent cette vue, c'est juste dommage de devoir dépendre d'un IDE.
    Ca pourrait peut-être impacter dans une organisation à grande échelle ou des centaines de devs vont mettre leur nez dans le header, mais ce n'est pas la situation du projet, alors je fais au plus efficace .
    Find me on github

  12. #12
    Membre régulier
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Août 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2012
    Messages : 44
    Points : 91
    Points
    91
    Par défaut
    Citation Envoyé par oodini Voir le message
    Cela sert à séparer la déclaration de l'implémentation.
    Sauf que ce n'est PAS une implémentation. Un "class template" n'est pas une class, il ne déclare rien. C'est juste un template pour que le compilateur copie-colle/remplace des trucs dedans quand le template est utilise.

    Il y a des différences fondamentales avec des class.
    Le compilateur a besoin de connaitre le corps des templates a chaque fois un template est utilise.
    Le compilateur s'en fiche des implémentations des classes "normales". Si t'oublie une implémentation, c'est le linker qui t'enguele, pas le compilateur.

    Citation Envoyé par oodini Voir le message
    Tout le monde sera également content si un include est mis à la fin des headers. Sauf les râleurs.
    Oui bon, apres il faut voir si ces plaintes sont légitimes. Je ne le pense pas!

  13. #13
    Membre à l'essai
    Homme Profil pro
    Collégien
    Inscrit en
    Avril 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Avril 2014
    Messages : 5
    Points : 14
    Points
    14
    Par défaut
    Un argument pratique pour la séparation: mettre le code template dans un .txx (ou .tpp...) séparé -- tout en gardant les déclarations dans le .h -- permet de pouvoir configurer sa librairie pour avoir au choix une librairie "tout header" ou une librairies avec le code template précompilé, pour un gain de temps de compilation parfois vertigineux. Voire, de proposer les deux.

    J'avoue que c'est surtout utile pour les librairies plutôt axées calcul où les types de template correspondent typiquement aux types arithmétiques de base. C'est néanmoins mon cas, et je trouve ça très utile.

  14. #14
    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 : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par forrestdg Voir le message
    Sauf que ce n'est PAS une implémentation. Un "class template" n'est pas une class, il ne déclare rien. C'est juste un template pour que le compilateur copie-colle/remplace des trucs dedans quand le template est utilise.
    Mais c'est malgré tout une implémentation.

    Le modèle de compilation fait qu'il est nécessaire que le compilateur connaisse le corps des templates mais ça n'en reste pas moins de l'implémentation.

  15. #15
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    user019, est-ce qu'utiliser extern (C++11) ne suffirait pas par hasard ?

    Citation Envoyé par gl Voir le message
    Mais c'est malgré tout une implémentation.
    D'accord !

    Citation Envoyé par gl Voir le message
    Le modèle de compilation fait qu'il est nécessaire que le compilateur connaisse le corps des templates
    Ca par contre, ce n'est pas vrai. Exemple, ce code compile et s'exécute sans erreur:

    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
    #include <iostream>
     
    template <typename T> struct Test {
      void Roger() const { std::cout << "Yeah" << std::endl; }
      T Marcel() const;
    };
     
    struct Test2 {
      int a_;
      Test2(Test<int> const& t) : a_(t.Marcel()) {};
    };
     
    int main() {
      Test<int> t1;
      t1.Roger();
      //Test2 t2(t1);
      return 0;
    }
    Si on décommente la ligne //Test2 t2(t1);, l'édition de lien échoue, mais pas la compilation . Le compilateur a besoin du corps des fonctions pour générer les symboles s'il n'en dispose pas, mais on peut très bien se contenter de déclarer puis fournir les symboles à l'édition de lien, ce que fait certainement user019.
    Find me on github

  16. #16
    Membre à l'essai
    Homme Profil pro
    Collégien
    Inscrit en
    Avril 2014
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Collégien

    Informations forums :
    Inscription : Avril 2014
    Messages : 5
    Points : 14
    Points
    14
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    user019, est-ce qu'utiliser extern (C++11) ne suffirait pas par hasard ?
    Non, ce n'est pas vraiment la même chose.

    Le but de mettre l'implémentation dans un .txx séparé est de pouvoir proposer une version précompilée qui est rapide à compiler avec. L'un des gains vient justemment du fait de se passer des .txx et des includes qui y sont. En effet le .h ainsi épuré ne contient alors que les .h qui sont nécessaire à la déclarations des templates, pas à leur implémentation. Cela peut briser de très nombreuses dépendances.

  17. #17
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par forrestdg Voir le message
    Sauf que ce n'est PAS une implémentation. Un "class template" n'est pas une class, il ne déclare rien. C'est juste un template pour que le compilateur copie-colle/remplace des trucs dedans quand le template est utilise.
    En fait, si. En général, je colle le code (l’« implémentation ») du template après sa déclaration (la déclaration complète, avec toutes les méthodes), tout dans le même fichier. Toutefois, je suis déjà tombé sur un cas où j’ai été obligé de séparer les deux, sans quoi, j’avais un problème d’inclusion insoluble (certaines méthodes de mon template utilisent des méthodes d’un autre objet qui a besoin de connaître mon template).

    Le cas est assez tordu, et il y a effectivement un couplage assez fort entre les deux classes en question, mais qui ne relève pas (ceci n’engageant bien sûr que moi) d’un problème de conception.

  18. #18
    Membre régulier
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Août 2012
    Messages
    44
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2012
    Messages : 44
    Points : 91
    Points
    91
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Toutefois, je suis déjà tombé sur un cas où j’ai été obligé de séparer les deux, sans quoi, j’avais un problème d’inclusion insoluble (certaines méthodes de mon template utilisent des méthodes d’un autre objet qui a besoin de connaître mon template).
    ce n'est pas un problème, il te faut forward declare ce dont tu as besoin et tout ira bien.

Discussions similaires

  1. definition de code au fichier.cpp
    Par info_ dans le forum C++
    Réponses: 9
    Dernier message: 05/04/2010, 12h51
  2. Fichier cpp et ActiveX
    Par 1300371 dans le forum Visual C++
    Réponses: 12
    Dernier message: 11/07/2006, 11h24
  3. plusieurs fichiers cpp
    Par elekis dans le forum C++
    Réponses: 2
    Dernier message: 11/05/2006, 06h36
  4. Fichier .cpp
    Par sourivore dans le forum Windows
    Réponses: 5
    Dernier message: 03/05/2006, 15h04
  5. Réponses: 7
    Dernier message: 22/11/2005, 14h05

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