DP visitor : comment spécialiser sans réécrire accept ?

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Salut,

D'habitude, lorsque j'implémente un DP visitor, pour éviter d'avoir à réécrire la fonction accept dans chaque classe fille, je fais ça :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Visited
{
public:
    //...

    virtual void accept(Visitor& visitor) = 0;
};

template<typename Tag>
class ConcreteVisited : public Visited
{
public:
    //...

    virtual void accept(Visitor& visitor)
    {
        visitor.visit(*this);
    }
};

Et pour avoir une nouvelle classe fille, je fais un alias et éventuellement une spécialisation selon les besoins.

Cependant, lorsque je spécialise, je suis obligé de réécrire la fonction accept. J'aimerais donc éviter de devoir réécrire accept quand je spécialise.

Au pire, vu que la fonction accept ne changera jamais, je peux me permettre de la réécrire plusieurs fois, mais bon, il vaudrait mieux pouvoir éviter.

Merci d'avance !

EDIT : La solution est assez simple, finalement (merci à jo_link_noir) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Visited
{
public:
    //...

    virtual void accept(Visitor& visitor) = 0;
};

template<typename Derived, class VisitedBase = Visited>
struct ConcreteVisited : VisitedBase
{
    void accept(Visitor& visitor) override
    {
        visitor.visit(static_cast<Derived&>(*this));
    }
};

struct ConcreteVisited1 : ConcreteVisited<ConcreteVisited1> {};
struct ConcreteVisited2 : ConcreteVisited<ConcreteVisited2> 
{
    // ...
};

Édité par mehdidou99

Plus on apprend, et, euh… Plus on apprend. | Coliru, parfait pour tester ses codes sources !

+0 -0
Auteur du sujet

D'habitude, c'est ce que je fais, mais je me suis rendu compte que ce coup-ci, j'avais vraiment écrit n'importe quoi : une fausse solution pour un faux problème. De plus, je me trouvais dans l'impossibilité d'éditer (mon portable fonctionne bizarrement…) au moment où je me suis rendu compte des inepties que je débitais. C'est pourquoi dans ce cas, j'ai choisi de masquer. Mais dans l'absolu, je suis d'accord. :)

Pour me faire pardonner, je donne tout de même une solution pour ne pas avoir à réécrire accept, même si je ne sais pas si elle en vaut la chandelle :

 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
class Visited
{
public:
    //...

    virtual void accept(Visitor& visitor) = 0;
};

template<typename Tag>
class JeNeSaisPasQuelNomDonner : public Visited
{
};

template<typename Tag>
class ConcreteVisited : public JeNeSaisPasQuelNomDonner<Tag>
{
public:
    virtual void accept(Visitor& visitor)
    {
        visitor.visit(*this);
    }
};

//On peut faire directement un alias :
struct Tag1 {};

using ConcreteVisited1 = ConcreteVisited<Tag1>;

//Ou on peut spécialiser sans réécrire accept :
struct Tag2 {};

template<>
class JeNeSaisPasQuelNomDonner<Tag2> : public Visited
{
    //...
};

using ConcreteVisited2 = ConcreteVisited<Tag2>

En fait, JeNeSaisPasQuelNomDonner agit un peu comme une classe de politique.

Du coup, un titre plus adapté serait : DP visitor : comment spécialiser sans réécrire accept ?

EDIT : @artragis : Merci, je n'aurais pas pu démasquer moi-même.

EDIT 2 : J'ai réédité le premier message pour qu'il corresponde au vrai problème.

Édité par mehdidou99

Plus on apprend, et, euh… Plus on apprend. | Coliru, parfait pour tester ses codes sources !

+1 -0

Cette réponse a aidé l'auteur du sujet

Pourquoi ne pas faire du CRTP classique ?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
template<typename Derived, class VisitorBase = Visited>
struct ConcreteVisitor : VisitorBase
{
    void accept(Visitor& visitor) override
    {
        visitor.visit(static_cast<Derivied&>(*this));
    }
};

struct ConcreteVisited1 : ConcreteVisited<ConcreteVisited1> {};
struct ConcreteVisited2 : ConcreteVisited<ConcreteVisited2> 
{
  // ...
};
+1 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte