A more generic visitor pattern


Question

I'm sorry if my question is so long and technical but I think it's so important other people will be interested about it

I was looking for a way to separate clearly some softwares internals from their representation in c++

I have a generic parameter class (to be later stored in a container) that can contain any kind of value with the the boost::any class

I have a base class (roughly) of this kind (of course there is more stuff)

class Parameter 
{
public:
    Parameter()
    template typename<T> T GetValue() const { return any_cast<T>( _value ); }
    template typename<T> void SetValue(const T& value) { _value = value; }
    string GetValueAsString() const = 0;
    void SetValueFromString(const string& str) const = 0;
private:
    boost::any _value;
}

There are two levels of derived classes: The first level defines the type and the conversion to/from string (for example ParameterInt or ParameterString) The second level defines the behaviour and the real creators (for example deriving ParameterAnyInt and ParameterLimitedInt from ParameterInt or ParameterFilename from GenericString)

Depending on the real type I would like to add external function or classes that operates depending on the specific parameter type without adding virtual methods to the base class and without doing strange casts

For example I would like to create the proper gui controls depending on parameter types:

Widget* CreateWidget(const Parameter& p)

Of course I cannot understand real Parameter type from this unless I use RTTI or implement it my self (with enum and switch case), but this is not the right OOP design solution, you know.

The classical solution is the Visitor design pattern http://en.wikipedia.org/wiki/Visitor_pattern

The problem with this pattern is that I have to know in advance which derived types will be implemented, so (putting together what is written in wikipedia and my code) we'll have sort of:

struct Visitor 
{
  virtual void visit(ParameterLimitedInt& wheel) = 0;
  virtual void visit(ParameterAnyInt& engine) = 0;
  virtual void visit(ParameterFilename& body) = 0;
};

Is there any solution to obtain this behaviour in any other way without need to know in advance all the concrete types and without deriving the original visitor?


Edit: Dr. Pizza's solution seems the closest to what I was thinking, but the problem is still the same and the method is actually relying on dynamic_cast, that I was trying to avoid as a kind of (even if weak) RTTI method

Maybe it is better to think to some solution without even citing the visitor Pattern and clean our mind. The purpose is just having the function such:

Widget* CreateWidget(const Parameter& p)

behave differently for each "concrete" parameter without losing info on its type

1
9
5/23/2017 12:19:34 PM

For a generic implementation of Vistor, I'd suggest the Loki Visitor, part of the Loki library.

4
8/29/2008 12:02:18 AM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon