I'm using a library (opencv actually) provided by others. There's a
class called "Mat", in which stored chunk of data with many types.
Also, there's a member in the Mat class to indicate which data the
class stores.
I want to use the class more intelligently to avoid checking series
data types in running time.
for example, in the original codes:
switch(type_flag) {
case INT_TYPE:
break;
case FLOAT_TYPE:
break;
... ...
}
How can I avoid this?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
This is commonly called a "variant" type.
> I want to use the class more intelligently to avoid checking series
> data types in running time.
>
> for example, in the original codes:
> switch(type_flag) {
> case INT_TYPE:
> break;
> case FLOAT_TYPE:
> break;
> ... ...
> }
>
> How can I avoid this?
I'd suggest a visitor pattern as one approach. I'd also take a look at =
the
documentation of Boost.Variant, which is a library for such variant =
types
that already provides some of the necessary code for visitors.
Uli
--
Sator Laser GmbH
Gesch=C3=A4ftsf=C3=BChrer: Thorsten F=C3=B6cking, Amtsgericht Hamburg HR =
B62 932
You could do
template<typename F>
typename F::result_type visit(F f, Mat& m)
{
switch(m.type_flag)
{
case INT_TYPE:
return f(*static_cast<int*>(m.void_ptr));
case FLOAT_TYPE:
return f(*static_cast<float*>(m.void_ptr));
...
}
}
then
struct my_visitor
{
typedef void result_type;
void operator()(int i)
{
std::cout << "it's an int " << i << std::endl;
}
void operator()(float f)
{
std::cout << "it's a float " << f << std::endl;
}
};
visit(m, my_visitor());
Now, you can also define the visitor inline, but that requires some
pretty advanced trickery or C++0x lambdas.
> I'm using a library (opencv actually) provided by others. There's a
> class called "Mat", in which stored chunk of data with many types.
> Also, there's a member in the Mat class to indicate which data the
> class stores.
>
> I want to use the class more intelligently to avoid checking series
> data types in running time.
>
> for example, in the original codes:
> switch(type_flag) {
> case INT_TYPE:
> break;
> case FLOAT_TYPE:
> break;
> ... ...
> }
This is a textbook application of polymorphism.
Define an abstract base class, let's say MatBase, which contains a Mat (or a
pointer to one). For each data type, define a derived class: IntMat, FloatMat,
etc. Finally, define a factory function CreateMat, which takes a Mat as
argument and spits out the appropriate derived class wrapper.
The factory function will still have to contain a switch on type_flag, but
thereafter all type-dependent processing can be done in virtual functions
declared but not defined in BaseMat and implemented for each data type in the
corresponding derived class, so that no switching is required.
Best wishes,
Matthew
--
http://homepages.ihug.co.nz/~m_collett
Actually, I would call this a textbook anti-application of polymorphism.
It may work for operations such as "transpose" or
"invert", maybe "multiply by an integer", but there is not much
useful stuff you can be put into virtual functions (unless you
use dynamic casting as a simple alternative to a switch)...
Others have already suggested using a variant and a visitor.
If necessary and applicable, polymorphic design might come in
a layer above this one.
--
Dragan
http://en.wikipedia.org/wiki/Visitor_pattern
was suggested by:
http://groups.google.com/group/comp.lang.c++.moderated/msg/1c3236126f6980c0?hl=en
and that uses polymorphism; hence, I'm not sure it is an example
of an anti-application. Could you further justify this conclusion
in light of the Visitor_pattern?
TIA.
-Larry
--
I'd say that trying to coerce different datatypes into a common interface,
so that you can handle them by just using the interface to the baseclass is
what is wrong. This leads to bloat in the interface (the baseclass needs
everything and the kitchensink) while the implementations become spare and
typically throw a "not supported" exceptions for most functions because
they can't sensibly implement them.
The visitor pattern (a.k.a. double dispatch) is typically implemented using
a single virtual function, so it indeed uses polymorphism. The difference
is that the actual handling is defined by the visitor, and that is supplied
by the code calling the code, not by the implementation of the the actual
types that are being visited. That also means that this caller can make a
decision how it wants to handle different situations and it also avoids the
interface bloat and sparse implementation.
Uli
--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
I was referring to the quoted design as anti-application. It is
neither a variant nor a visitor pattern. And later I mentioned
that other people have already suggested a good solution.
--
Dragan