tags:

views:

146

answers:

3

I have a class that uses an "add-on" template to add additional functionality as below:

template< class T >
class AddOn_A
{
public: 
    int SomeFuncA()
    {
        T* pT = static_cast< T* >( this );
        return pT->DoSomething() + 1;
    };
};

class CMyClass : public AddOn_A< CMyClass >
{
public:
    int DoSomething()
    {
        return 100;
    };
};

int _tmain(int argc, _TCHAR* argv[])
{
    CMyClass A;
    _ASSERT( A.SomeFuncA() == 101 );

    return 0;
}

Now I would like to extend this such that CMyClass can accept different add-ons like AddOn_B.

template< class T >
class AddOn_B
{
public: 
    int SomeFuncB()
    {
        T* pT = static_cast< T* >( this );
        return pT->DoSomething() + 2;
    };
};

template< class AddOn >
class CMyClass : public AddOn
{
public:
    int DoSomething()
    {
        return 100;
    };
};

int _tmain(int argc, _TCHAR* argv[])
{
    // error C3203: 'AddOn_A' : unspecialized class template can't be used as a template argument for template parameter 'AddOn', expected a real type
    // error C2955: 'AddOn_A' : use of class template requires template argument list
    CMyClass< AddOn_A > A;
    _ASSERT( A.SomeFuncA() == 101 );

    // same errors here
    CMyClass< AddOn_B > B;
    _ASSERT( B.SomeFuncB() == 102 );

    return 0;
}

Unfortunately, each Add_On requires CMyClass as a template parameter which requires an Add_On, etc... I'm in a requirement loop.

Is there some template magic I can use to get the functionality I'm looking for? Is there a better method of doing this?

Thanks, PaulH

+2  A: 

If I understood your question right (not sure), then what you need is a template template argument:

template< template<class> class AddOn >
class CMyClass : public AddOn< CMyClass<AddOn> > {
  // ...
};
sbi
Okay, now that line you added fails with the error C3203: 'CMyClass' : unspecialized class template can't be used as a template argument for template parameter '<unnamed-symbol>', expected a real type.It would have to be ": public AddOn<CMyClass<AddOn<CMyClass...>>>"
PaulH
@PaulH: Sorry, I indeed had a syntax error. This should compile now.
sbi
A: 

Apparently you are trying to use the famous Curiously Recurring Template Pattern.

I am not sure of what you exactly want to do, but you might get away with another solution:

What if you used two classes:

 class Base {};

 class MyClass: public AddOn<Base> {};

You may also use a Policy Based approach:

 class PolicyA_A {};
 class PolicyA_B {};

 class PolicyB_A {};
 class PolicyB_B {};

 template <class PolicyA, class PolicyB>
 class MyClass: private PolicyA, private PolicyB {};

 typdef MyClass<PolicyA_A, PolicyB_A> MyClassAA;

The idea is to delegate part of the job to policies to add flexibility.

Last but not least you may use a Decorator approach:

 class Base {};

 template <class T>
 class AddOn_A: public T {};

 class MyClass: public AddOn_A< AddOn_B< Base > > {};

It allows you to get rid of the virtual inheritance by suppressing the Multi Inheritance and making the hierarchy linear.

Matthieu M.
I think the Decorator approach is perfect. Thanks for your help.
PaulH
A: 

Why can you not just use:

CMyClass< AddOn_A<CMyClass> > A;
_ASSERT( A.SomeFuncA() == 101 );
Martin York