c++: Calling a template method of a base class from a template child class though multilevel inheritance

StackOverflow https://stackoverflow.com/questions/23439017

Question

I'm looking to call a method of a base class A from a child class D that inherits it through C::A and B::A.

template <class PType>
class A
{
public:
    template <class ChildClass>
    void Func( void )
    {
        std::cout << "Called A<PType>::Func<ChildClass>" << std::endl;
    }
};

template <class PType>
class B : public A<PType>
{
};

template <class PType>
class C : public A<PType>
{
};

class D : public B<int>, public C<int>
{
public:
    D()
    {
        static_cast<B<int>*>( this )->A<int>::Func<D>();
        static_cast<C<int>*>( this )->A<int>::Func<D>();
    }
};

This works as expected, D calls both B::A::Func and C::A::Func with a template argument of the child class when initialized. This doesn't seem to work when D is a template class, however.

template <class PType>
class D2 : public B<PType>, public C<PType>
{
public:
    D2()
    {
        //expected primary-expression before ‘>’ token
        //expected primary-expression before ‘)’ token
        static_cast<B<PType>*>( this )->A<PType>::Func< D2<PType> >();
        static_cast<C<PType>*>( this )->A<PType>::Func< D2<PType> >();
    }
};

The problem seems to be the template argument D2 to Func, but can't figure it out beyond that.

Was it helpful?

Solution

When you are working with a name whose value/type/template status is dependent on a template type parameter, you must disambiguate which one it is for the compiler manually.

This is to make the parsing far easier, and able to be done long before you pass a type into the template.

You may think that is obviously a template function call, but the < and > could be comparisons, and the template functions could be values or types or whatever.

By default, such dependent names are assumed to be values. If you want them to treat one as a type, use typename. If you want to treat one as a template, use template as a keyword.

So something like this:

   static_cast<B<PType>*>( this )->template A<PType>::template Func< D2<PType> >();

now, when you are interacting with a fully instantiated template this is not required. So:

   static_cast<B<int>*>( this )->A<int>::Func< D2<PType> >();

consists of a fully instantiated template type B<int>, so A's category is no longer dependent on a (locally undetermined) template argument. Similarly, ->A<int> is a fully instantiated template type, so ::Func is no longer dependent on a (locally undetermined) template argument.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top