Bonjour.
Je dois stocker dans un conteneur des objets polymorphiques.
Ce qui m'oblige à utiliser des pointeurs.

Les classes en question n'ont pas de constructeur par défaut et ne sont ni copiables ni assignables.
Mais elles sont déplaçables et swappables.

Vu que le conteneurs est censé stocker les objets, il est responsable de leur création et de leur destruction.
J'utilise donc std::unique_ptr.

Le problème, c'est d'arriver à créer les bonnes instances d'objet.

La première idée qui m'est venue fut de faire une fonction clone dont le but est créer une copie par déplacement, allouée dynamiquement, à redéfinir dans les classes filles.
(Je sais, le nom n'est pas très bien choisi...)
Sauf qu'au final, toutes les redéfinitions auront la même tête, il y aura juste de nom de la classe (après new) qui changera.
Ça fait duplication de code...

Bon, voyons ce que les templates peuvent m'apporter...
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 A
{
 
  private:
    template <class T>
    static
    std::unique_ptr<A> clone(T&& x)
    {
        return std::unique_ptr( new T(std::move(x)) );
    }
 
  public:
    std::unique_ptr<A> clone()
    {
        return clone(std::move(*this));
    }
 
};
Je me disais que la fonction membre statique serait capable de déterminer le type réel de l'objet x.
Sauf que vu que je l'appelle depuis un A, elle ne peut pas...


Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A
{
 
  public:
    template <class T>
    static
    std::unique_ptr<A> clone(A&& x)
    {
        typedef typename std::remove_reference<T>::type type;
 
        return std::unique_ptr( new type(std::move(x)) );
    }
 
};
Commet cela, ça fonctionne déjà mieux.
J'ai juste oublié que lors de l'insertion :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
class container : private std::vector< std::unique_ptr<A> >
{
 
  private:
    typedef std::vector< std::unique_ptr<A> > _base;
 
  public:
    void insert(A&& x)
    {
        _base::push_back( A::clone(std::move(x)) );
    }
};
je passe encore via un A.


L'autre solution que je vois, c'est de rendre la fonction insert template, et d'y créer la copie.
Dans ce cas, on pourra se rendre compte à la compilation si l'on essaie d'insérer un objet qui n'hérite pas de A ?

Si vous avez d'autres suggestions, je suis preneur...