1

I've been facing a big challenge (for me, at least) regarding templates instancing and inheritance. Let's see this code:

class Convertible
{
    public:

    template<class T>
    T* AsPtrTo()
    {
        return reinterpret_cast<T*>(this);
    }
};

template<class T>
class TemplateBase : public Convertible
{
};

template<class T>
class TemplateDerived : public TemplateBase<T>
{
    public:

    void Method1(TemplateBase<T> t)
    {
        t.AsPtrTo<int>(); // <<<<<< ERROR
    }
};


int main()
{
    TemplateDerived<int> d;
    TemplateBase<int> b;
    d.Method1(b);

    return 0;
}

As you can see, there is a class, called Convertible, with only one template method that performs a type casting. There is also a template class that inherits from Convertible, and then another template class that inherits from the previous one. This last template class implements a method that uses the template method AsPtrTo which should be inherited from Convertible and instanced during compilation for the type T, used in the main function.

For some reason I can't understand, this fails. GCC 4.4.1 gives me this message:

error: expected primary-expression before 'int'

I've marked the line of the error.

I thought maybe one of the C++ experts here could lend me a hand.

Thanks everybody in advance!

Thund
  • 13
  • 3

2 Answers2

6

You need to use the keyword template as:

 t.template AsPtrTo<int>(); 

This has been discussed so many times that you will find innumerable number of posts on SO.

But here you will find one of the best explanation:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Thanks for your answer, I searched for a post related to this but I couldn't find anything :(, surely I used the wrong keywords. The problem is now clear for me, thanks again. – Thund Dec 18 '11 at 15:32
4

Try:

void Method1(TemplateBase<T> t)
{
    t.template AsPtrTo<int>();
}

The reason is that the compiler doesn't know what member functions t has at parse time, so it doesn't know if AsPtrTo is a template function or not. Because of this, it can't parse it properly without the hint.

As an example for why this is needed, consider the following code:

struct Foo
{
    template<int N> int foo(int x) { return x + N; }
};

struct Bar
{
    int foo;
}; 

template <typename T>
int baz(T t)
{
    return t.foo<0>(1);
}

At a glance, it looks like baz<Foo> would work, but baz<Bar> wouldn't, but it's the other way round!

Consider what happens if I call baz<Bar>

return t.foo<0>(1);

foo is a member variable, so when it sees the < it thinks it's a less-than operator, so it parses the expression like this:

return (t.foo < 0) > (1);

Which is a valid expression (after some implicit conversions to/from bool)!

The thing is, it parses the expression like that for both Foo and Bar, which is why the template keyword is needed. Compilers have to assume that it is not a template member function (unless you put that keyword there).

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168