views:

40

answers:

2
+2  Q: 

Template arguments

I have ClassA<ARG_TYPE> and ClassB<ARG_TYPE>. Now I want want to use ClassC, that has common ARG_TYPE and mentioned classes as template arguments.

ClassC<ARG_TYPE, ClassA<ARG_TYPE>, ClassB<ARG_TYPE>> is easy.

But is it possible do declare ClassC<ARG_TYPE, ClassA, ClassB> so that both A and B classes would know to use ARG_TYPE as their template argument?

+5  A: 

Yes, it can be done, through the use of "template template arguments".

Declare ClassC as follows :

template<typename Arg, 
    template<typename T_Arg> class T_ClassA, 
    template<typename T_Arg> class T_ClassB>
class ClassC
{
   typedef T_ClassA<Arg> MyClassA;
   typedef T_ClassB<Arg> MyClassB;

   // Use MyClassA and MyClassB
}; 

Use

ClassC<Arg, ClassA, ClassB> 

and it should work fine.

Benoît
A: 

It can be done, however I don't like this solution much.

The issue is that suppose I define:

template <class Arg, class Policy> class Polymorph;

which is a generalization of your MyClassA type but whose behavior can be changed (at compile-time) through the use of policies (think Allocator for standard container for example).

Then I just can't use your interface, because my class takes 2 parameters while your specification only works with one...

Therefore, I much prefer the first approach, even if a bit more verbose. In order to benefit from both you have 2 solutions (both involving duck-typing):

  • you just define a first class using the first approach and then a second class using the second approach which forwards the (now complete) arguments to the first. This way people with template classes that do not match your requirements will still be able to benefit from your work.
  • it's up to the user to provide the duck-typing for its class so that it creates a one argument class from a several arguments class. Inheritance and template don't mix well though so this may cause issues and I would favor the previous idea (put the burden on the library writer).

This changes with the advent of C++0x: the later solution becomes a template'd typedef which works much better :)

Here is an example in C++0x:

template <class Arg, template <class> class ClassA>
struct MyTemplate
{
  typedef ClassA<Arg> classA_type;
};

template <class Arg, class Policy> class Polymorph;

// C++0x required for following declaration
template <class Arg>
typedef Polymorph<Arg, ConservativePolicy> ConservativePolymorph;

typedef MyTemplate<int, ConservativePolymorph> MyTemplateC;

If you don't have C++0x available, shy away from this and re-use the STL way, even if it's more verbose.

Matthieu M.