yigal chripun Wrote:
> of the three above I think option 3 is the worst design and option 2 is my
> favorite design. I think that in reality you'll almost always want to define
> such an interface and I really can't think of any useful use cases for an
> unrestricted template parameter as in C++.
I think there are some. In C++ using "<<" to extract a type T to an output
stream is common. Similarly, you could do something like dividing (x.size() +
0.0)/x.capacity() to find the ratio of internal fragmentation, assuming most of
the containers in question have a capacity method. Another common example is
creating a type like "Optional<T>" which wraps up a boolean plus a T to allow
you to have "optional" values, e.g. the "this value is not set" concept.
template<class T> class Optional {
T x;
bool have;
public:
Optional(bool have1 = false) : have(have1) {}
Optional(T & x1) : x(x1), have(true){}
bool haveValue() { return have; }
T & get() { assert(have); return x; }
};
Which is useful for passing around lists of "configuration options" etc.
Essentially, any time you want to leverage a property common to a lot of
different objects and with the same API across all of them, but don't want to
(or can't) build that property into an inheritance diagram. Often in C++ the
reason you can't or don't add a virtual method (toString) to solve the same
problem is either that (1) you don't have access to the base class code, or (2)
it's a template and you can't have virtual templates.
As Bill Clinton said, "It depends on what the meaning of IS-A is."
Often a bunch of types have a kind of unrecognized "IS-A" relationship -- they
all have some common characteristic that is not recognized as common (by the
type system) until you come along to write code that deals with that
characteristic. (But if the T code is changing it's fragile to do this.)
Kevin