8

Regarding CRP if I want to implement a slight variation of it (using template template parameter) I get a compile error:

template <template <typename T> class Derived>
class Base
{
public:
    void CallDerived()
    {
        Derived* pT = static_cast<Derived*> (this);
        pT->Action(); // instantiation invocation error here
    }
};

template<typename T>
class Derived: public Base<Derived>
{
public:
    void Action()
    {
    }
};

I am not exactly sure one would chose this form (that does not compile for me) instead of using this though (this works)

template <typename Derived>
class Base
{
public:
    void CallDerived()
    {
        Derived* pT = static_cast<Derived*> (this);
        pT->Action();
    }
};

template<typename T>
class Derived: public Base<Derived<T>>
{
public:
    void Action()
    {
    }
};
Ghita
  • 4,465
  • 4
  • 42
  • 69

2 Answers2

11

This should compile as well. We just need to get the other template parameter specified explicitly

 template <typename T, template <typename T> class Derived>
 class Base
 {
 public:
     void CallDerived()
     {
        Derived<T>* pT = static_cast<Derived<T>*> (this);
        pT->Action(); // instantiation invocation error here
     }
 };

template<typename T>
class Derived: public Base<T,Derived>
{
public:
    void Action()
    {
    }
};
Dima Chubarov
  • 16,199
  • 6
  • 40
  • 76
  • 1
    Quite interesting one has to be explicit about typename T in declaration twice... Don't really understand why – Ghita Apr 29 '12 at 18:37
  • 1
    Just realized that derived has to transmit it's T parameter also. – Ghita Apr 29 '12 at 18:46
5

In the first example, the class template actually takes template template parameter, not just template parameter, as you've written:

template <template <typename T> class Derived>
class Base
{
     //..
};

So this code doesn't make sense:

Derived* pT = static_cast<Derived*> (this);
pT->Action(); // instantiation invocation error here

Here Derived is a template template argument which needs template argument which you didn't provided to it. In fact, in the CallDerived() function, you cannot know the type you need to provide to it, in order to do what you intend to do.

The second approach is the correct solution. Use it.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    But how do I provide the template argument in first case.. Using derived * pt does not work either – Ghita Apr 29 '12 at 18:30
  • 1
    @Ghita: `T` is not known in the base class. Other solution has explained as to how you can pass `T` to the base. But that is not needed, as you should go for the second solution. – Nawaz Apr 29 '12 at 18:32
  • 1
    Sometimes T is needed in the Base class. E.g. when having a member `T Action();` For sure, you could use a traits class that gives a T for every Derived class, but sometimes you want T and Derived to vary independently. In that case, you want the [first] approach with a template + a template-template parameter. – TemplateRex Apr 30 '12 at 08:11