C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Re: Visitors and MixIn-s

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Allan Odgaard
Guest





PostPosted: Fri Sep 12, 2003 10:21 am    Post subject: Re: Visitors and MixIn-s Reply with quote



Radu Grigore wrote:

Quote:
Is there any way to avoid this code duplication?

Since you do not say what the MixIn functions actually do, or how
"similar" the code is in the other visitors, it's difficult to suggest
concrete solutions.

But with respect to the code you did write, which you wanted to avoid
having to replicate for another visitor, then I suggest something
along these lines:

template <typename T>
T dispatch (AbstractEl* baseEl, T visit)
{
if(ConcreteEl_A* el = dynamic_cast<ConcreteEl_A*>(baseEl))
visit(el);
else if(ConcreteEl_B* el = dynamic_cast<ConcreteEl_B*>(baseEl))
visit(el);
return visit;
}

template <typename _Type>
struct MixIn
{
template <class T> void operator() (T* el) { ... }
};

Which now allow you to write code like this:

dispatch(element, MixIn<TypeA>());
dispatch(element, MixIn<TypeB>());

You can make 'dispatch' an AbstractEl member function, maybe naming it
'receive', allowing code like: "element->receive(MixIn<TypeA>());"

The function uses dynamic_cast and is linear in the number of types,
you can make it constant time if you store your own type tag in the
abstract base class.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Radu Grigore
Guest





PostPosted: Sat Sep 13, 2003 8:35 am    Post subject: Re: Visitors and MixIn-s Reply with quote



[email]Duff (AT) DIKU (DOT) DK[/email] (Allan Odgaard) wrote in message news:<689e217.0309111312.49f47472 (AT) posting (DOT) google.com>...
Quote:
Radu Grigore wrote:

Is there any way to avoid this code duplication?

Since you do not say what the MixIn functions actually do, or how
"similar" the code is in the other visitors, it's difficult to suggest
concrete solutions.

I think my original post is unclear since your answer seems to address
a different problem. I'll repeat part of the context:

class ConcreteElA : public AbstractEl, public MixIn<TypeA>;
class ConcreteElB : public AbstractEl, public MixIn<TypeA>;
class ConcreteElC : public AbstractEl;

The abstract visitor is:

class AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* element) {VisitChildren(element)};
virtual void Visit(ConcreteElB* element) {VisitChildren(element)};
virtual void Visit(ConcreteElC* element) {VisitChildren(element)};
private:
void VisitChildren(AbstractElement* element)
{
// "pseudocode"
FOREACH(iterator, element->childs) it->Accept(this);
}
}

Some concrete visitors (not all) look like:

class ConcreteVisitorA : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* element)
{ doMixIn(element); VisitChildren(element); };
virtual void Visit(ConcreteElB* element)
{ doMixIn(element); VisitChildren(element); };
virtual void Visit(ConcreteElB* element) { /* do soemthing else */
}

private:
template <typename U> doMixIn(U* element)
{
// Do something specific for this visitor and
// call some functions defined in the MixIn, like:
... cout << element->GetTAsString() << endl; ...
}
}

The MixIn class looks like this (althought I don't think it's
relevant):

template class MixIn
{
public:
MixIn(const T& t_) {t = t_;}
T GetT() {return t;}
string GetTAsString() {return to_str[t];}
private:
map<T, string> to_str;
T t;
};

My problem IS NOT writing the function doMixIn<U>() in every visitor
since they do different thinks. This is why they belong to the
visitors and not a different class (eg. MixIn in your example).

The problem IS that I have to CALL doMixIn for both ConcreteElA and
ConcreteElB in every concrete visitor. In other words I need to
distinguish between sets {is inherited from MixIn}, {is NOT inherited
from MixIn} in every ConcreteVisitor, even thou these sets don't
depend on the concrete visitor.

In your proposed solution I'd still have to call dispatch. And worse,
I can't do different things for different concrete visitors.

Thanks for taking time to answer.

regards,
radu

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Graeme Prentice
Guest





PostPosted: Sat Sep 13, 2003 7:56 pm    Post subject: Re: Visitors and MixIn-s Reply with quote



On 13 Sep 2003 04:35:32 -0400, [email]radugrigore (AT) ieee (DOT) org[/email] (Radu Grigore)
wrote:


[snip]

Quote:

My problem IS NOT writing the function doMixIn<U>() in every visitor
since they do different thinks. This is why they belong to the
visitors and not a different class (eg. MixIn in your example).

The problem IS that I have to CALL doMixIn for both ConcreteElA and
ConcreteElB in every concrete visitor. In other words I need to
distinguish between sets {is inherited from MixIn}, {is NOT inherited
from MixIn} in every ConcreteVisitor, even thou these sets don't
depend on the concrete visitor.



Since I'm a little bit interested in the visitor pattern at the moment,
I decided to have a look at your problem. One possibility is the code
below - there are actually two versions of the "same" code here, one
using dynamic_cast (AbstractVisitorMixin1, ConcreteVisitorA1) and an
alternative using static_cast (AbstractVisitorMixin2, ConcreteVisitorA2)
- they produce the same result but dynamic_cast will most likely be
slower. The static_cast version does a kind of "manual dynamic cast" to
cross cast the pointer.

I'll describe the code in terms of the static_cast version.

The common code that you wish to avoid repeating is in
AbstractVisitorMixin2 class. It calls the appropriate doMixin function
via its template parameter type. The ConcreteVisitorA2 class inherits
from both ConcreteVisitorA_IMPL2 and AbstractVisitorMixin2 class.
ConcreteVisitorA_IMPL2 corresponds to your ConcreteVisitorA class. You
may not need the GetAbstractVisitorPtr() member if the ConcreteVisitorA
class doesn't need to access anything in the abstract_visitor class or
base classes - you may also need to forward the access via the
ConcreteVisitorA2 class if you access a non public member.


In the AbstractVisitorMixin2 class you may be able to make use of
// ::boost::is_base_and_derived<mixin,T>::value
to auto detect inheritance from mixin and call doMixin for those types
only. ( www.boost.org typetraits )

Unless you have lots of visitor classes, you may be better off with your
original method and perhaps add the auto detect of inheritance from the
mixin class. Also, if the doMixin function doesn't need access to other
members of the visitor class, you can probably simplify the code below
by moving the doMixin function to a separate template class and pass
that template class to AbstractVisitorMixin2 instead of what's below.

If you're using VC6 you may have a problem with this code but GCC,
Comeau and Borland execute it correctly.

Graeme


#include <iostream>

struct mixin{};

struct ConcreteElA : public mixin { static const int x = 991;};
struct ConcreteElB : public mixin { static const int x = 992;};
struct ConcreteElC { static const int x = 993;};

class AbstractVisitor
{
protected:
void VisitChildren(ConcreteElA* p)
{
std::cout << 'n' << (p->x + 1000);
}
void VisitChildren(ConcreteElB* p)
{
std::cout << 'n' << (p->x + 1000);
}
void VisitChildren(ConcreteElC* p)
{
std::cout << 'n' << (p->x + 1000);
}
public:
virtual void Visit(ConcreteElA* element) {};
virtual void Visit(ConcreteElB* element) {};
virtual void Visit(ConcreteElC* element) {};
};

template <typename T>
class AbstractVisitorMixin1 : public AbstractVisitor
{
virtual void Visit(ConcreteElA* element)
{
T *p = dynamic_cast<T*>(this);
if (p)
p->doMixIn(element);
VisitChildren(element);
}
virtual void Visit(ConcreteElB* element)
{
T *p = dynamic_cast<T*>(this);
if (p)
p->doMixIn(element);
VisitChildren(element);
}

};


class ConcreteVisitorA_IMPL1
{
protected:
void Visit(ConcreteElC* p)
{
std::cout << 'n' << (p->x + 2000);
};
friend class AbstractVisitorMixin1<ConcreteVisitorA_IMPL1>;
private:
template <typename U> void doMixIn(U* element)
{
// Do something specific for this visitor and
// call some functions defined in the MixIn, like:
std::cout << 'n' << element->x;
}
};


class ConcreteVisitorA1 : public ConcreteVisitorA_IMPL1,
public AbstractVisitorMixin1<ConcreteVisitorA_IMPL1>
{
virtual void Visit(ConcreteElC* element) // do something else
{
ConcreteVisitorA_IMPL1::Visit(element);
}
};




//=======================================================================
// second method using static_cast instead of dynamic_cast
//=======================================================================


template <typename T1>
class AbstractVisitorMixin2 : public AbstractVisitor
{
//public:
virtual T1 * GetImplPtr()=0;

virtual void Visit(ConcreteElA* element)
{
// call a template function here instead of this, perhaps
GetImplPtr()->doMixIn(element);
VisitChildren(element);
}
virtual void Visit(ConcreteElB* element)
{
GetImplPtr()->doMixIn(element);
VisitChildren(element);
}
};


class ConcreteVisitorA_IMPL2
{
protected:
void Visit(ConcreteElC* p)
{
std::cout << 'n' << (p->x + 2000);
};
virtual AbstractVisitor* GetAbstractVisitorPtr()=0;
friend class AbstractVisitorMixin2<ConcreteVisitorA_IMPL2>;
private:
template <typename U> void doMixIn(U* element)
{
// Do something specific for this visitor and
// call some functions defined in the MixIn, like:
std::cout << 'n' << element->x;
}
};


template <typename T1>
class ConcreteVisitor : public T1,
public AbstractVisitorMixin2<T1>
{
virtual AbstractVisitor* GetAbstractVisitorPtr()
{
return static_cast<AbstractVisitor*>(this);
}
virtual T1 * GetImplPtr()
{
return static_cast<T1*>(this);
}
};

class ConcreteVisitorA2 : public ConcreteVisitor<ConcreteVisitorA_IMPL2>
{
virtual void Visit(ConcreteElC* element) // do something else
{
ConcreteVisitorA_IMPL2::Visit(element);
}
};


int main()
{
ConcreteVisitorA1 a1;
ConcreteVisitorA2 a2;
ConcreteElA xa;
ConcreteElB xb;
ConcreteElC xc;
AbstractVisitor *p1 = &a1;
p1->Visit(&xa);
p1->Visit(&xb);
p1->Visit(&xc);
p1 = &a2;
p1->Visit(&xa);
p1->Visit(&xb);
p1->Visit(&xc);
}




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Allan Odgaard
Guest





PostPosted: Sat Sep 13, 2003 11:57 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

Radu Grigore wrote:

Quote:
Is there any way to avoid this code duplication?
[...]
I think my original post is unclear since your answer seems to address
a different problem. I'll repeat part of the context:

It's certainly true that I found it hard to understand the actual
problem, but I think my solution can still be used, I'll elaborate:

Quote:
The abstract visitor is:

class AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* element) {VisitChildren(element)};
virtual void Visit(ConcreteElB* element) {VisitChildren(element)};
virtual void Visit(ConcreteElC* element) {VisitChildren(element)};

Add a catch-all like this:
virtual void VisitAbstract(AbstractEl* element) { };
And change all the other member functions to do:
VisitAbstract(element); VisitChildren(element);

Quote:
class ConcreteVisitorA : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* element)
{ doMixIn(element); VisitChildren(element); };
virtual void Visit(ConcreteElB* element)
{ doMixIn(element); VisitChildren(element); };
virtual void Visit(ConcreteElB* element) { /* do soemthing else */
}

Here you can now eliminate the visit member functions for ConcreteElA
and ConcreteElB. Then overload the VisitAbstract() member function to
use my previous dispatch function, to get to the template method with
proper (template type) arguments (either change dispatch to invoke
doMixIn or change the doMixIn member function to an operator()).

Although my original intend was for you to ditch the entire visitor
code in favour of the dispatch solution, which can be made look pretty
much like a standard visitor, with the additional feature that it can
do templated member functions with dynamic dispatch on type.

Quote:
My problem IS NOT writing the function doMixIn<U>() in every visitor
since they do different thinks. This is why they belong to the
visitors and not a different class (eg. MixIn in your example).

As I understand it, your problem is that you have to CALL the doMixIn
from every visitor member function, and you need to do it in the most
derived class, so that you will get to the proper implementation --
thus with 10 derived visitor classes and 10 different element classes,
you'd need to write essentially 100 identical member functions.

With the above you CAN eliminate all these member functions, and let
the VisitAbstract do it instead (through the use of dispatch).
However, you will still need to implement VisitAbstract in each
derived class as far as I can tell, but that would cut it down to 10
member functions instead of 100, and you can still overload the Visit
member function for the types which should not be handled by the
generic doMixIn().

I hope I have made myself more clear this time and actually understood
your problem! :-)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Grzegorz Jakacki
Guest





PostPosted: Tue Sep 16, 2003 6:33 am    Post subject: Re: Visitors and MixIn-s Reply with quote

Hi,

Perhaps something like this is sufficient:

template <class DerivedVisitor>
class MixinAwareVisitor : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
virtual void Visit(ConcreteElA* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
};

class ConcreteVisitorA : public MixinAwareVisitor<ConcreteVisitorA>
{
public:
template <class T>
void doMixin(T* elem) { ... }
};

'doMixin()' has to be public, but code is quite short. (Also make sure
that 'MixinAwareVisitor<T>' is abstract, otherwise you violate LSP.)

Alternatively you can hide doMixin by adding

class AbstractVisitor
{
...
protected:
template <class T, class Derived> doMixin(T* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
}
};

changing the call in 'MixinAwareVisitor' to

virtual void Visit(ConcreteElA* elem)
{
doMixin<Derived>(elem);
AbstractVisitor::Visit(elem);
}


and making 'AbstractVisitor' a friend of 'ConcreteVisitorA'.

BR
Grzegorz

Graeme Prentice <gp1 (AT) paradise (DOT) net.nz> wrote

Quote:
On 13 Sep 2003 04:35:32 -0400, [email]radugrigore (AT) ieee (DOT) org[/email] (Radu Grigore)
wrote:
[snip]


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Graeme Prentice
Guest





PostPosted: Tue Sep 16, 2003 12:01 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

On 16 Sep 2003 02:33:17 -0400, [email]jakacki (AT) hotmail (DOT) com[/email] (Grzegorz Jakacki)
wrote:

Quote:
Hi,

Perhaps something like this is sufficient:

I don't think so. Perhaps you should try your code and post a complete
example.

Quote:

template <class DerivedVisitor
class MixinAwareVisitor : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* elem)
{
static_castdoMixin(elem);
AbstractVisitor::Visit(elem);
}
virtual void Visit(ConcreteElA* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
};

What is "Derived" in the above code? Did you mean DerivedVisitor?



Quote:

class ConcreteVisitorA : public MixinAwareVisitor {
public:
template void doMixin(T* elem) { ... }
};

You can't pass an incomplete class as a template parameter to the base
class. That's the reason I had to use multiple inheritance in my code.

Note to Radu - BTW, if you're reading this Radu, the static_cast in my
code is unnecessary (as you probably know), since Derived* to Base* is
an implicit conversion with public inheritance, but it shows there's an
"unusual" pointer conversion happening.

Graeme


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Lorenzo Bettini
Guest





PostPosted: Tue Sep 16, 2003 8:35 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

Radu Grigore wrote:
Quote:
I have a Visitor hierarchy used to implement operations on a
composite. Because some of the concrete elements (of the visited
hierarchy) share some common code I have used Mix-In like this:

Hi

Since you use the visitor pattern (in order to simulate double
dispatch), maybe doublecpp could be useful:

http://www.lorenzobettini.it/software/doublecpp/index.html

a preprocessor for implementing double dispatch in C++

hope this helps
Lorenzo

--
+-----------------------------------------------------+
Quote:
Lorenzo Bettini ICQ# lbetto, 16080134 |
PhD in Computer Science |
Dip. Sistemi e Informatica, Univ. di Firenze |
Tel +39 055 4796741, Fax +39 055 4796730 |
Florence - Italy (GNU/Linux User # 158233) |
Home Page : http://www.lorenzobettini.it |
http://music.dsi.unifi.it XKlaim language |
http://www.lorenzobettini.it/purple Cover Band |
http://www.gnu.org/software/src-highlite |
http://www.gnu.org/software/gengetopt |
http://www.lorenzobettini.it/software/gengen |
+-----------------------------------------------------+



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Grzegorz Jakacki
Guest





PostPosted: Wed Sep 17, 2003 8:31 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

Graeme Prentice <gp1 (AT) paradise (DOT) net.nz> wrote

Quote:
On 16 Sep 2003 02:33:17 -0400, [email]jakacki (AT) hotmail (DOT) com[/email] (Grzegorz Jakacki)
wrote:

Hi,

Perhaps something like this is sufficient:

I don't think so. Perhaps you should try your code and post a complete
example.

Attached.

Quote:
template <class DerivedVisitor
class MixinAwareVisitor : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* elem)
{
static_castdoMixin(elem);
AbstractVisitor::Visit(elem);
}
virtual void Visit(ConcreteElA* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
};

What is "Derived" in the above code? Did you mean DerivedVisitor?

Exactly.

Also 'using' declaration is missing from the class.

Quote:
class ConcreteVisitorA : public MixinAwareVisitor<ConcreteVisitorA
{
public:
template void doMixin(T* elem) { ... }
};

You can't pass an incomplete class as a template parameter to the base
class.

Why not?

Quote:
That's the reason I had to use multiple inheritance in my code.

I don't think it is valid.

Best regards
Grzegorz

PS: Note that e.g. gcc-2.95 will choke on the attached code, as it cannot
handle 'using' correctly. This can be worked around by manually forwarding
'Visit(ConcreteElC*)' in 'MixinAwareVisitor<>'. Tested with gcc-3.2.1
and Comeau on-line.

------------------ mixin-visitor.cc ------------------------
#include <iostream>
#include <string>

using namespace std;

template <class T>
struct MixIn
{
T GetSomething() { return T(); }
};

class ConcreteElA;
class ConcreteElB;
class ConcreteElC;

class AbstractVisitor
{
protected:
void VisitChildren(ConcreteElA* p)
{
cout << "VisitChildren(ConcreteElA*)" << endl;
// ...
}
void VisitChildren(ConcreteElB* p)
{
cout << "VisitChildren(ConcreteElB*)" << endl;
// ...
}
void VisitChildren(ConcreteElC* p)
{
cout << "VisitChildren(ConcreteElC*)" << endl;
// ...
}
public:
virtual void Visit(ConcreteElA* element) { VisitChildren(element); };
virtual void Visit(ConcreteElB* element) { VisitChildren(element); };
virtual void Visit(ConcreteElC* element) { VisitChildren(element); };
};

struct AbstractEl { /*...*/ };
struct ConcreteElA : public AbstractEl, public MixIn struct ConcreteElB : public AbstractEl, public MixIn<double> {/*...*/};
struct ConcreteElC : public AbstractEl {/*...*/};


template <class DerivedVisitor>
class MixinAwareVisitor : public AbstractVisitor
{
public:
using AbstractVisitor::Visit;

virtual void Visit(ConcreteElA* elem)
{
static_cast<DerivedVisitor*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
virtual void Visit(ConcreteElB* elem)
{
static_cast<DerivedVisitor*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
};

class ConcreteVisitorA : public MixinAwareVisitor<ConcreteVisitorA>
{
public:
template <class Concrete>
void doMixin(Concrete* elem)
{
cout << "mixin says: [" << elem->GetSomething() << "]"
<< endl;
}
};

int main()
{
ConcreteElA xa;
ConcreteElB xb;
ConcreteElC xc;

ConcreteVisitorA visitor;
visitor.Visit(&xa);
visitor.Visit(&xb);
visitor.Visit(&xc);
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Graeme Prentice
Guest





PostPosted: Thu Sep 18, 2003 9:41 am    Post subject: Re: Visitors and MixIn-s Reply with quote

On 17 Sep 2003 16:31:18 -0400, [email]jakacki (AT) hotmail (DOT) com[/email] (Grzegorz Jakacki)
wrote:

[snip]

Quote:

template <class DerivedVisitor
class MixinAwareVisitor : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* elem)
{
static_castdoMixin(elem);
AbstractVisitor::Visit(elem);
}
virtual void Visit(ConcreteElA* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
};

What is "Derived" in the above code? Did you mean DerivedVisitor?

Exactly.

Also 'using' declaration is missing from the class.

class ConcreteVisitorA : public MixinAwareVisitor<ConcreteVisitorA
{
public:
template void doMixin(T* elem) { ... }
};

You can't pass an incomplete class as a template parameter to the base
class.

Why not?

That's the reason I had to use multiple inheritance in my code.

I don't think it is valid.

I see that your code compiles. I assumed that you couldn't dereference
a pointer to an incomplete type.
static_castdoMixin(elem);

Can you explain why this compiles?

Graeme


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Radu Grigore
Guest





PostPosted: Fri Sep 19, 2003 11:01 am    Post subject: Re: Visitors and MixIn-s Reply with quote

Hi All,

Thank you for the answers. In this post I'll try summarize them. There
are three different approaches that have been suggested:

1. Allan Odgaard: Use a templated dispatch function that contains
a type commutator.

The idea is to have a catch-all visit method in the concrete visitor
and call the dispatch function from there. This way, if you have N
visitors and M elements instead of putting NxM calls to doMixIn you
only have N calls to the dispatch function. This actually works pretty
well for me because the main problem is the large number of concrete
elements (M).

However, there are two problems. First, I'm not sure how well this
mixes Smile with the code for default traversal. Here is what I mean:

class AbstractVisitor {
public:
virtual void Visit(ConcreteElement* element); // (a)
virtual void Visit(AbstractElement* element); // (b) catch-all
};

class ConcreteVisitor : public AbstractVisitor {
public:
void Visit(AbstractElement* element) {dispatch(...);} // (c)
};

ConcreteVisitor cv;
ConcreteElement ce;
cv.Visit(&ce);

The last statement will probably call (a), not (c). The answer would
be to move the processing from (a) methods to method (b). When I tried
the compiler misteriously failed and I have decided not to spend time
on it. Now that I think of it... this change is a good idea even if
not using the dispatch method.

The second problem is the type commutator itself. It incurs a little
run-time penalty and is somehow "against" the visitor pattern idea of
not explicitely dealing with types in code.


2. Grzegorz Jakacki: Move the selection code in a base class which
is templated by the derived class type.

This seems the most simple and effective solution. Thanks. The sample
code sent illustrates very well the idea. You just create a templated
MixAwareVisitor which contains the selection code. The class is
templated because the selection code needs to know the type of the
concrete (derived) visitor in order to call the correct doMixIn.

Luckily I'm using gcc 3.3 Smile So this is the solution I'll use.


3. Graeme Prentice: Move the implementation of the concrete visitor
in class A, the selection code in class B, inherit C from both A
and B; C contains some type casts in order to correctly select
methods from A or B. Then inherit D from C and put here some
"forwarding" methods (which, as far as I can tell) are needed
because of multiple inheritance of methods with same name. Uf... :)

I must confess I had some trouble in trying to understand your
solution. This probably means that if I'll use it then I'll be unable
to maintain it Smile It did raised some questions. For example in the
ConcreteVisitor you inherit from both AbstractVisitor (via
MixinAwareVisitor<>) and ConcreteVisitor_IMPL. This two classes
contain a Visit method. You use a "forwarding" method in
ConcreteVisitor to select between the two as far as I can tell.

What are the general rules of behavior when methods with identical
signatures are inherited from different classes (when multiple
inheritance is used)?

Another question is how exactly was I supposed to use
is_base_and_derived in order to simplify the selection code. What I
know is that ::boost::is_base_and_derived<U, T>::value evaluates to
true or false (or is it an integer? anyway, not relevant here) at
compile time and thus can by used exactly as a constant. I can write
for example if (..is_base_and..) {...}.
You meant something along the lines of solution (1) but instead of
calling dispatch function in the catch-all function do something like
the following ?

// Warning: this is some kind of pseudocode since I don't
// really see how it can be done.
ConcreteVisitor::Visit(AbstractElement* el)
{
if (is_base_and_derived<typeid(el), MixIn)
{
doMixIn<typeid(el)>(el);
}
...
}

4. Lorenzo Bettini: multimethod preprocessor for C++

I had just a short glimpse at this preprocessor. It does not seem
justified to use it if I don't have more than _double_ dispatch. The
visitor solution is well known and already implemented. It's good to
know about it thou.

regards,
radu

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Graeme Prentice
Guest





PostPosted: Sat Sep 20, 2003 3:09 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

On 19 Sep 2003 07:01:59 -0400, [email]radugrigore (AT) ieee (DOT) org[/email] (Radu Grigore)
wrote:

Quote:

3. Graeme Prentice: Move the implementation of the concrete visitor
in class A, the selection code in class B, inherit C from both A
and B; C contains some type casts in order to correctly select
methods from A or B. Then inherit D from C and put here some
"forwarding" methods (which, as far as I can tell) are needed
because of multiple inheritance of methods with same name. Uf... Smile

No that's not why the forwarding method is there, but I won't try to
explain any further, since Grzegorz's code compiles. As far as I can
tell, the C++ standard gives no guarantees about *when* a virtual member
of a template class is instantiated. If it's instantiated at the same
time as the class, then Grzegorz's code won't compile because of the
incomplete type. The incomplete type problem is why in my original
code, the ConcreteVisitor class inherits both the implementation class
and the AbstractVisitor class (multiple inheritance). I suspect a good
compiler will instantiate a virtual member of a template class at the
end of a translation unit (unless it's called explicitly before then) so
it's probably ok to use Grzegorz's code. I suspect my code is not as
complex as you think - it just moves the implementation of the
ConcreteVisitor class (doMixin etc) into a second base class, but it's
obviously best not to do this if you don't have to.


Quote:

I must confess I had some trouble in trying to understand your
solution. This probably means that if I'll use it then I'll be unable
to maintain it Smile It did raised some questions. For example in the
ConcreteVisitor you inherit from both AbstractVisitor (via
MixinAwareVisitor<>) and ConcreteVisitor_IMPL. This two classes
contain a Visit method. You use a "forwarding" method in
ConcreteVisitor to select between the two as far as I can tell.

What are the general rules of behavior when methods with identical
signatures are inherited from different classes (when multiple
inheritance is used)?

An unqualified call is a compile time error.


Quote:

Another question is how exactly was I supposed to use
is_base_and_derived in order to simplify the selection code.

My apologies. I didn't think this suggestion through very far as I ran
out of time and just wanted to bring it to your attention - but you're
right, it's no help at all.

Graeme

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Lorenzo Bettini
Guest





PostPosted: Mon Sep 22, 2003 10:18 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

Radu Grigore wrote:
Quote:
4. Lorenzo Bettini: multimethod preprocessor for C++

I had just a short glimpse at this preprocessor. It does not seem
justified to use it if I don't have more than _double_ dispatch. The
visitor solution is well known and already implemented. It's good to
know about it thou.

Actually my preprocessor ONLY implements double dispatch, and not
multiple dispatch. I had suggested as a way of automatically
implementing the visitor pattern :-)

Lorenzo

--
+-----------------------------------------------------+
Quote:
Lorenzo Bettini ICQ# lbetto, 16080134 |
PhD in Computer Science |
Dip. Sistemi e Informatica, Univ. di Firenze |
Tel +39 055 4796741, Fax +39 055 4796730 |
Florence - Italy (GNU/Linux User # 158233) |
Home Page : http://www.lorenzobettini.it |
http://music.dsi.unifi.it XKlaim language |
http://www.lorenzobettini.it/purple Cover Band |
http://www.gnu.org/software/src-highlite |
http://www.gnu.org/software/gengetopt |
http://www.lorenzobettini.it/software/gengen |
+-----------------------------------------------------+



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Grzegorz Jakacki
Guest





PostPosted: Mon Sep 22, 2003 10:22 pm    Post subject: Re: Visitors and MixIn-s Reply with quote

Graeme Prentice <gp1 (AT) paradise (DOT) net.nz> wrote

Quote:
On 17 Sep 2003 16:31:18 -0400, [email]jakacki (AT) hotmail (DOT) com[/email] (Grzegorz Jakacki)
wrote:

[snip]


template <class DerivedVisitor
class MixinAwareVisitor : public AbstractVisitor
{
public:
virtual void Visit(ConcreteElA* elem)
{
static_castdoMixin(elem);
AbstractVisitor::Visit(elem);
}
virtual void Visit(ConcreteElA* elem)
{
static_cast<Derived*>(this)->doMixin(elem);
AbstractVisitor::Visit(elem);
}
};

What is "Derived" in the above code? Did you mean DerivedVisitor?

Exactly.

Also 'using' declaration is missing from the class.

class ConcreteVisitorA : public MixinAwareVisitor<ConcreteVisitorA
{
public:
template void doMixin(T* elem) { ... }
};

You can't pass an incomplete class as a template parameter to the base
class.

Why not?

That's the reason I had to use multiple inheritance in my code.

I don't think it is valid.

I see that your code compiles. I assumed that you couldn't dereference
a pointer to an incomplete type.
static_castdoMixin(elem);

Can you explain why this compiles?

I was under impression that DerivedVisitor is a complete type when the
enclosing function is instantiated, but I am not sure now.

As far as I understand it in this particular case clauses 14.6.4.1.p1
and 14.6.4.1p4 are contradictory for virtual functions of class
template which are not referenced from template specialization. I will
try to clarify it in a separate thread.

The hint why this may work comes from Josuttins/Vandervoorde "C++
Templates. The Complete Guide":

"In practice, most compilers delay actual instantiation of
noninline
function templates to the end of translation unit. (...) The
intention of the C++ designers was for this to be a valid
implementation technique, but standard does not make this clear."

BR
Grzegorz


Quote:
Graeme

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.