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 :

factory & références


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    screetch
    Invité(e)
    Par défaut factory & références
    Je bloque un peu sur mon problème la; je souhaite interdire l'opérateur new sur un objet pour forcer a utiliser une fonction "create" :

    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
    #include <cstdlib>
    #include <cstdio>
     
    class refcountable
    {
    public:
        template< typename T >
        static T* create()
        {
            return new T;
        }
        template< typename T, typename P1 >
        static T* create(P1 p1)
        {
            return new T(p1);
        }
    private:
        void* operator new(const size_t size) { return ::operator new(size); }
        void  operator delete(void* memory) { return ::operator delete(memory); }
    };
     
    struct A : public refcountable
    {
        A() { };
        A(int& i) { };
    };
    ainsi ici, on ne peut plus ecrirel'objectif au final c'est que la méthode create renvoie au final un smart pointer au lieu du raw pointeur, du coup on a plus moyen d'avoir un pointeur sur A
    (en ajoutant que l'opérateur & sera interdit... niark niark)
    interdiant donc totalement le raw pointeur. c'est du moins l'objectif.
    Mais ici je suis face a un petit problème :

    avant il etait impossible d'appeler
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    A a(1);
    main.cc:32: error: no matching function for call to 'A::A(int)'
    main.cc:26: note: candidates are: A::A(int&)
    main.cc:25: note:                 A::A()
    main.cc:24: note:                 A::A(const A&)
    mais la, il est parfaitement possible d'appeler
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A* a = refcountable::create<A>(1);
    PIRE (et dangereux)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    A a;
    A a2(a); //copie de a
    se transforme en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    A* a = refcountable::create<A>();
    A* a2 = refcountable::create<A>(*a); // la fonction create va recevoir un temporaire qui va etre créé, puis détruit, on a plus la référence directe sur a
    comment puis-je résoudre ces problèmes ? vous voyez ou je veux en venir ?

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Je pense que tu as compris que l'instanciation de create se fait avec P1 par valeur et non par référence, d'où ces temporaires.
    En lecture rapide de ton code, je vois deux solutions :
    -> Regarder du côté de l'artillerie Boost pour la programmation générique ;
    -> Le faire à la main à coup de enable_if et de SFINAE sur la signature des constructeurs de A pour que P1 corresponde. Quelque chose comme ça (écrit complètement à la volée donc sans aucun sens mais pour donner l'idee) :
    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
     
       template< typename T, typename P1 >
        static T* create(P1 p1)
           enable_if<T::T(P1)>
        {
            return new T(p1);
        }
     
       template< typename T, typename P1 >
        static T* create(P1 &p1)   --> En fait des argument_trait<P1>::ref_type
           enable_if<T::T(P1 &)>  --> idem
        {
            return new T(p1);
        }
     
       template< typename T, typename P1 >
        static T* create(P1 const &p1)   --> En fait des argument_trait<P1>::const_ref_type
           enable_if<T::T(P1 const &)>  --> Idem
        {
            return new T(p1);
        }
    C'est le genre d'idée que je commencerais par creuser.

  3. #3
    screetch
    Invité(e)
    Par défaut
    oui je voyais bien que ca se faisait par valeur.
    mais si je le passe en référence, alors il y a du code parfaitement valide qui ne voudra pas compiler
    et si je le passe en référence const, on ne pourra plus appeler le constructeur si celui-ci veut des références (c'est malgré tout ce sur quoi je m'oriente, dans la mesure ou du code valide pourrait être rejeté mais aucun code invalide accepté)

    l'inconvénient du enable_if c'est que la j'ai mis un exemple avec des constructeurs a 0 et 1 arguments, mais si il y en a 10 ? on va devoir tester les 10 ? ca va mettre un gros bordel.

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Avec 10 arguments, tu n'aura plus le problème de la construction par copie. Tu dois pouvoir alors décliner en ref et ref const qui sont 2 types différents. Mais si ta classe n'a qu'une signature en non const, cela peut poser problème. Après, pour gérer la combinatoire, faudrait passer par Boost.Preprocessor (peut être avec les variadic templates?).

  5. #5
    screetch
    Invité(e)
    Par défaut
    rah tu m'as grillé de quelques secondes :p
    oui, effectivement il suffit d'avoir deux methodes, une qui prend en const et une en non const. ca genere 2^10 methodes cependant non ? (chaque parametre peut prendre deux valeurs, const ou non const)

  6. #6
    Membre Expert
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Par défaut
    Regarde du côté de boost:pp pour générer autant de code

  7. #7
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    Regarde #include "boost/call_traits.hpp"

    Sinon aussi #include "boost/make_shared.hpp" où on ne s'embarasse pas des reférences non const.
    Pareil pour les in_place_factory: pas de place pour les non const.

  8. #8
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par défaut
    Citation Envoyé par screetch Voir le message
    rah tu m'as grillé de quelques secondes :p
    oui, effectivement il suffit d'avoir deux methodes, une qui prend en const et une en non const. ca genere 2^10 methodes cependant non ? (chaque parametre peut prendre deux valeurs, const ou non const)
    Et qu'une seule en C++0x. Est-que ton compilo gère le perfect forwading+variadic template ?

  9. #9
    Membre éclairé
    Inscrit en
    Avril 2005
    Messages
    1 110
    Détails du profil
    Informations forums :
    Inscription : Avril 2005
    Messages : 1 110
    Par défaut
    De même, très vite, comme ceci, sans avoir trop réfléchi non plus:
    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
    template< typename T >
    class refcountable
    {
    public:
        static refcountable<T>* create()
        {
            return new T;
        }
        template< typename P1 >
        static refcountable<T>* create(P1 const & p1)
        {
            return new T(p1);
        }
    private:
        void* operator new(const size_t size) { return ::operator new(size); }
        void  operator delete(void* memory) { return ::operator delete(memory); }
    };
     
    struct A : public refcountable<A>
    {
        A() { };
        A(int& i) { };
    };
    Mais bon, comme j'ai déjà écrit mon smart ptr qui fait ce que tu souhaites (sauf que le mien n'est même pas intrusif), je vais pas trop creuser .

Discussions similaires

  1. [Livres/Références] Vos avis..
    Par Community Management dans le forum Livres
    Réponses: 6
    Dernier message: 25/07/2005, 19h31
  2. Références / tutoriels MFC COM
    Par DivisionParZéro dans le forum MFC
    Réponses: 3
    Dernier message: 03/02/2004, 17h49
  3. Passage d'un tableau par référence?
    Par sebduth dans le forum C
    Réponses: 9
    Dernier message: 16/07/2003, 18h32
  4. [Concept] Table de référence
    Par matlo dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 20/01/2003, 15h01

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