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 :

Arguments différents selon le template


Sujet :

Langage C++

  1. #1
    Membre habitué
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Par défaut Arguments différents selon le template
    Bonjour,

    Je souhaiterais utilizer des templates pour diminuer le nombre grandissant de versions similaires d'un type de classe.
    Typiquement, nous avons un ensemble de factory dont le seul but est de créer l'objet final à utiliser.
    Dans cette classe factory, nous avons plusieurs methods standards.
    1) une methode clone qui recrée la meme factory
    2) un constructeur dont les paramètres dependent de la classe finale qui sera crée
    3) une function create qui crée l'objet final en utilisant les paramètres du constructeur de la factory qui sont dépendant du type de classe à créer (tout en gérant la mémoire).

    Je souhaiterais remplacer cette series de factories par une seule qui prendrait en classe T (template) la classe finale à créer. Cependant, je ne sais pas si cela est possible étant donné la difference de paramètres à indiquer suivant T.
    Est-ce possible ?

    Merci d'avance.

    Matthieu

  2. #2
    Membre Expert
    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
    Par défaut
    Hello,

    Regarde du coté des templates variadic.

    Quelque chose du genre est possible (non testé)
    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, class... Args>
    struct Factory {
     
        std::tuple<Args...> m_defaultArgs;
     
        Factory(Args const&... args): m_defaultArgs(args...) { }
        Factory(Factory const&) = default;
     
        Factory clone() const { return Factory(*this); }
     
        T create(Args const&... args) const { return T(args...); }
        T create() const { return apply(create, m_defaultArgs); }
    };
     
    struct Foo { Foo(int, double); };
    Factory<Foo, int, double> fac(3, 4.0);
    auto fac2 = fac.clone();
    auto foo0 = fac.create();
    auto foo1 = fac.create(1, 2.0);
    Avec la fonction apply tirré d'ici : SO
    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
    // ------------- UTILITY---------------
    template<int...> struct index_tuple{}; 
     
    template<int I, typename IndexTuple, typename... Types> 
    struct make_indexes_impl; 
     
    template<int I, int... Indexes, typename T, typename ... Types> 
    struct make_indexes_impl<I, index_tuple<Indexes...>, T, Types...> 
    { 
        typedef typename make_indexes_impl<I + 1, index_tuple<Indexes..., I>, Types...>::type type; 
    }; 
     
    template<int I, int... Indexes> 
    struct make_indexes_impl<I, index_tuple<Indexes...> > 
    { 
        typedef index_tuple<Indexes...> type; 
    }; 
     
    template<typename ... Types> 
    struct make_indexes : make_indexes_impl<0, index_tuple<>, Types...> 
    {}; 
     // ----------UNPACK TUPLE AND APPLY TO FUNCTION ---------
    #include <tuple>
    #include <iostream> 
     
    using namespace std;
     
    template<class Ret, class... Args, int... Indexes > 
    Ret apply_helper( Ret (*pf)(Args...), index_tuple< Indexes... >, tuple<Args...>&& tup) 
    { 
        return pf( forward<Args>( get<Indexes>(tup))... ); 
    } 
     
    template<class Ret, class ... Args> 
    Ret apply(Ret (*pf)(Args...), const tuple<Args...>&  tup)
    {
        return apply_helper(pf, typename make_indexes<Args...>::type(), tuple<Args...>(tup));
    }
     
    template<class Ret, class ... Args> 
    Ret apply(Ret (*pf)(Args...), tuple<Args...>&&  tup)
    {
        return apply_helper(pf, typename make_indexes<Args...>::type(), forward<tuple<Args...>>(tup));
    }

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Il faudrait peut-être passer par de la spécialisation de template.
    Et du CRTP pour le clone.

    exemple pour le clonage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template <typename T>
    struct clonable {
        T clone() const {return *this;}
    };
     
    template <typename Generated>
    class factory : public clonable< factory<Generated> > {
    public:
        factory(factory const&); //constructeur de copie pour le clonage
    };

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Billets dans le blog
    21
    Par défaut
    Dans mon idée la Factory avait pour principal intérêt de retourner des objets de classes différentes dans une hiérarchie de classe. Je ne suis pas sûr qu'une Factory spécialisée pour un type, et encore moins pour un constructeur d'un type, ait un véritable intérêt dans la conception d'un programme, si? Et si c'était le cas, plutôt que de faire une classe nouvelle, utiliser une combinaison de std::make_shared et std::bind fait aussi bien l'affaire.
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    std::make_shared<Circle>(10, 5, 7); <=> Circle_factory.create(10, 5, 7);
    auto Circle_10_5_7_factory = std::bind(std::make_shared<Circle>, 10, 5, 7);
    auto Circle_ptr = Circle_10_5_7_factory(); <=> Circle_1057_factory.create()

    Si les constructeurs des différentes classes de la hiérarchie ne prennent pas les mêmes arguments, alors l'affaire se complique

  5. #5
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    ta solution m'a l'air bien sympa.

    Cela dit, l'idée de base ressemble au pattern abstract factory.

  6. #6
    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,

    Heuu, juste une petite question...

    Une fonction clone() pour une factory ???? tu es sur que c'est utile ???

    La factory est une classe qui présente une sémantique d'entité. Et donc, par définition, chaque factory est identifiable de manière unique et non ambigüe. Mais, en plus, chaque factory s'occupe de créer un type d'objet bien particulier, ce qui la rend encore plus facilement identifiable de manière unique et non ambigüe : tu ne vas pas t'adresser à l'usine de harengs surgelés si tu veux obtenir une boite de conserve de... petits pois et carottes!

    Enfin, la création de nouveaux éléments devrait être centralisée à un seul et unique endroit (enfin, comprenons nous bien :un endroit unique part type d'élément créé) car, autrement, tu ne vas pas t'y retrouver. Et même si ce n'était pas le cas, ce serait quand même toujours la même factory qui s'occuperait de créer l'élément dont tu as besoin.

    Si bien que, au final, tu dois garantir par construction le fait qu'il n'existe et n'existera jamais qu'une seule instance de ta fabrique... Mais attention! il ne s'agit pas d'en faire un singleton pour la cause, vu que ta fabrique n'a aucune raison d'être accessible "depuis n'importe où"!.

    D'ailleurs, on peut même aller jusqu'à se demander s'il faut ne serait-ce qu'une seule instance de la fabrique, vu que nous pourrions très bien décider d'utiliser des fonctions statiques!

    Enfin, bref : la fonction clone() pour une factory n'a absolument aucun intérêt et ce n'est ni fait ni à faire

    Au passage : évite les fonctions clone() de manière générale : si l'on dit d'un type de donnée qu'il a sémantique d'entité, c'est bien parce qu'il doit être identifiable de manière unique et non ambigüe et qu'il y a donc forcément des données qui permettent cette identification. Eléments qui seraient -- en toute logique -- dupliqué par la fonction clone, vu qu'il s'agirait de créer... une copie conforme.

    Une fonction clone() est donc une aberration conceptuelle au niveau des classes ayant sémantique d'entité et ... n'a aucun intérêt au niveau des classes ayant sémantique de valeur (merci pour elles : le constructeur de copie fait le job )
    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

  7. #7
    Membre habitué
    Inscrit en
    Février 2010
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Février 2010
    Messages : 11
    Par défaut
    Bonjour,

    Tout d'abord, merci pour vos réponses.
    Ensuite, j'ai commence à regarder le variadic template. Il s'agit d'un outil très intéressant.

    Pour ce qui est du CRTP, quel est réllement son objectif ? Quel probleme est-il suppose régler généralement ?

    Pour les factory en elle-même, un graphe d'objets effectue un processing. Ces objets dont les paramètres sont modifiées par la factory dont les paramètres sont modifiés dont une couche supérieure va les créer pour adapter les paramètres selon un scenario. La copie est donc nécessaire pour reutilizer certains composants en multi threading en copiant le résultat plutôt que de tout recalculer.

    Merci.

    Matthieu

Discussions similaires

  1. Affichage différent selon texte dans une case
    Par pingoo78 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 22/11/2005, 16h32
  2. tailles d'input différentes selon les postes (?)
    Par mch_27 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 4
    Dernier message: 26/10/2005, 11h21
  3. [Interface graphique]Composant différents selon le PC
    Par Cyborg289 dans le forum Interfaces Graphiques en Java
    Réponses: 3
    Dernier message: 01/08/2005, 10h05
  4. CSS : fichier include différent selon chaque resolution
    Par Sylvain245 dans le forum Mise en page CSS
    Réponses: 8
    Dernier message: 31/03/2005, 17h57
  5. UNION de deux SELECT avec nombre d'arguments différents
    Par orus8 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 16/07/2004, 14h32

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