Derek <> wrote in news::
> I'm not sure you want to deal with the combinatorial
> explosion of using the visitor pattern. After all,
> there are 5 storage classes (constant, uniform,
> varying, facevarying, and vertex) and 10 types
> (float, integer, vector, color, normal, point, matrix,
> double, hpoint, and string). And each combination
> can be a scalar or an array. Yikes!
That's exactly the point.
Having such huge visitors seemed like a bad idea.
On the other hand, visitor guarantees that every subtype will be serviced
individually in the code.
> I propose a very simple strucutre (off the top of my
> head):
>
> class Variable
> {
> public:
> //...
> private:
> std::string m_varName;
> StorageType m_storageType;
> DataType m_dataType;
> int m_arrayLength;
> int m_elementLength;
> std::vector<float> m_data;
> };
>
> Now your algorithms can 'switch' based on type type if
> they have to. I think you will find that many operations
> (e.g., linear interpolation) don't care about the type
> at all.
I've been considering a similar design, except that the main data was
separated into respective derived classes.
That is:
class Variable {
std::string m_name;
StorageType m_storage_type;
int m_size; // ==0 : scalar, >0 - array
public:
virtual void AcceptVisitor(Visitor&) const = 0;
// ... accessors, etc.
};
class FloatVariable : public Variable {
std::vector<float> m_data;
public:
//...
};
class StringVariable : public Variable {
std::vector<std::string> m_data;
public:
//...
};
// etc...
This way, I could dispatch based on the actual data type, and use
conditionals for the storage type and/or array specification.
But then ... I'd probably end up with such conditionals in every visitor,
which is kind of contradictory to the whole design. Why bother with
visitor at all when there will be switches everywhere, anyway?
On the other hand, considering the fact that the storage specifier is
only giving a new meaning for array dimensions, I thought about turning
it into a kind of templated policy class, which would only determine the
algorithms for operations on the data regardless of the type...
E.g.
// only one element to copy
struct UniformStorage {
template <class IterT>
static void Copy(IterT to, IterT from)
{ *to = *from; } // just one value to copy here
// ...
};
// nvertices elements to copy
class VaryingStorage {
int m_nvertices;
public:
VaryingStorage(int nvertices) : m_nvertices(nvertices) { }
template <class IterT>
static void Copy(IterT to, IterT from) {
for (int i=0; i!=m_nvertices; ++i) {
*to = *from;
++to; ++from;
}
}
};
And then use those policies as template arguments for FloatVariable et
al.
This technique, however, rules out the GOF style visitation, because
virtual functions cannot be templates.
Unless all templates are given explicitly...
// in visitor
virtual void Visit(FloatVariable<UniformStorage> const&)
//...
So here we go back to the huge-visitor maintenance problem, because every
possible combination of variable with storage class must be given
explicitly...
Uhh too much coffee I guess...
Cheers
|