I have a design where I have a std::list of base pointers that I’d like to transform into a parallel list that adds behavior. The problem I’m having is that the object that I’m trying to use to do the transform doesnt know what the actual types are when it is invoked.
It’s quite possible that I’m missing something subtle and that there is an easy fix. However, if this is a design flaw (I’ve seen this suggested in other posts) what is the appropriate way to approach this?
Suppose the following:
class Sprite { /* ... */ };
class Character : public Sprite {};
class Markup : public Sprite {};
These are constructed (based on some input) into a std::list< Sprite * >. What I’d like to do is eventually take the list and transform it into a parallel structure suitable for output operations. For instance, given:
class HTMLSprite { /* ... */ };
class HTMLCharacter : public HTMLSprite {};
class HTMLMarkup : public HTMLSprite {};
I’d ideally like to do something like
std::transform(sprites.begin (), sprites.end (), html.begin (), HTMLConvert);
with something like
struct HTMLConvert_ {
HTMLSprite * operator () (const Character * c) { return new HTMLCharacter (); }
HTMLSprite * operator () (const Markup * c) { return new HTMLMarkup (); }
} HTMLConvert;
Now, I get the error
call of `(HTMLConvert) (const Sprite* const&)' is ambiguous
HTMLSprite* HTMLConvert::operator()(const Character*) const <near match>
Which leads me to my question. What is the best solution to this problem – redesign or otherwise?
Thanks.
In addition to JoshD’s suggestion, you can keep the door open for other transformations by using the visitor pattern.
Add a method
dispatch_visitto the Sprite hierarchy, using covariant return types:This allows each object to notify the converter of its dynamic type — essentially, a dynamic dispatch into the parallel type, or even a parallel type hierarchy. Everything else pretty much works as your code is written… the best candidate is chosen among the
operator()()functions of the converter, based on the static parameter type.Oh, you’ll need to add the “missing function” to the converter:
Hmm, that repetitive function could be encapsulated by a template… this only seems to work in C++0x if you want the
visitabletemplate to automatically determine the return type ofdispatch_visit. If you don’t likeprincipal_baseyou can factor it out.