4

I have a class template that happens to have the same name as a member function template of some classes. Now another function template gets instantiated with one of the classes with the member function template in question. To call the member function template within this function template I need to use the template keyword, I understand this and have no problem with that. However, I need to use the scope resolution operator (I just found out that's what that's called) :: to specify I mean the class' member function template and not the class template and I don't understand why.

That's a lot of templated things so let me give an example:

    //class with same name as member function below.
    //must be class template or error doesn't show up.
    //also no error if this is a function template instead of class
    template <class T>
    struct f
    {
    };

    struct Base
    {
        //function with same name as struct above,
        //no error if this is not templated
        template <int N>
        void f(){}
    };

    //template function that will be instantiated with T=Base.
    //no error if this is not templated
    template <class T>
    void g(T t)
    {
        //I understand why template keyword is needed here,
        //but not why T:: is needed
        t.T::template f<0>();
        //t.template f<0>(); gives error.
    }

The error in question is (from g++-4.7)

    error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> struct f’
    error:   expected a type, got ‘0’

It seems the compiler parses f<0>() on the commented out line (without scope resolution operator) as trying to instantiate an object of type struct f<0>. I don't know why it is doing this, I thought it should be able to see from the t.template that I'm trying to access the member function template.

I'd like to understand what is going on here, why is T:: needed in this case, other than to placate the compiler?

It seems that there is no problem under MSVC and Clang, so it seems to a g++-specific issue.

SirGuy
  • 10,660
  • 2
  • 36
  • 66

2 Answers2

1

I think it has to do with Two phase lookup. Especially Steve Jessops notes in the answer are are important.

Community
  • 1
  • 1
Jan Herrmann
  • 2,717
  • 17
  • 21
  • Are you saying that it's tripping up during the first phase? How can the syntax (what's checked during the first phase) `t. template f<0>()` possibly refer to the `struct f` such that `T::` is necessary to disambiguate it? – SirGuy May 15 '13 at 13:19
  • @GuyGreer Yes I think it sees f and interprets it as a non dependent name and fails instanciating the template. On the other hand msvc doesn't implement two phase lookup and there is no error. I tried clang 3.0 (on linux) and it compiles, too. – Jan Herrmann May 15 '13 at 14:16
  • clang compiles even t.f<0>(); – Jan Herrmann May 15 '13 at 14:30
  • From [temp.dep.type]/8 follows: `T` is a dependent type. From [temp.dep.expr]/1+3 follows: any expression involving `t` is type-dependent. From [temp.dep]/1 follows: in `t.template f<0>()`, `t.template f<0>` is a dependent name. – dyp May 15 '13 at 14:57
0

This might work

template <class T>
void g(T t)
{
    t.T::template f<0>(); 
}
Arun
  • 2,087
  • 2
  • 20
  • 33