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

Le problème exposé dans ce sujet a été résolu.

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> 
{
    // ...
};
+0 -0

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.

+1 -0

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> 
{
  // ...
};
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

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