[g++] call of a parent method of parent template class fails



  • code:

    #include <iostream>
    
    template<typename type>
    struct Parent {
        void foo() { std::cout << "Parent::foo()" << std::endl; }
    };
    
    template<typename type>
    struct Child : Parent<type> {
        void bar() { foo(); } // line 10
    };
    
    int main()
    {
        Parent<int> p;
        p.foo();
    }
    

    g++ output:

    $ g++ test.cpp -o test
    test.cpp: In member function `void Child<type>::bar()':
    test.cpp:10: error: there are no arguments to `foo' that depend on a template parameter, so a declaration of `foo' must be available
    test.cpp:10: error: (if you use `-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
    

    I can get rid of this error by using this->foo(); or using Parent<type>::foo;, but I don't understand why this doesn't work my way.

    greetings and thanks in advance



  • I can get rid of this error by using this->foo(); or using Parent<type>::foo;, but I don't understand why this doesn't work my way

    This is a peculiarity of the so called two-phase-name-lookup.
    Specifically, a non-dependent name is never looked up in a base class that depends on a template paramter.

    C++ Standard schrieb:

    In the definition of a class template or in the definition of a member of such a template that appears outside of the template definition, if a base class of this template depends on a template-parameter, the base class scope is not examined during name lookup until the class template is instantiated.

    In your example, the unqualified call to foo() can only be bound to a function declared in Child or in namespce-scope. The base of Child is not considered because it depends on the template-parameter type. The rationale for this rule is that otherwise name lookup would have to be delayed until templates are instantiated. Otherwise succeeding specialization would pose a problem
    Consider:

    template<typename type>
    struct Parent {
        void foo() { std::cout << "Parent::foo()" << std::endl; }
    };
    
    template<typename type>
    struct Child : Parent<type> {
        void bar() { foo(); } // line 10
    };
    
    template <>
    struct Parent<int> {
    
    };
    
    void f() {
      Child<int> c;
      c.bar();
    }
    

    As you can see, the compiler may not simply bind a name to a name contained in a dependent base class, because the meaning of this name may change when the template is specialized.

    So in order to not having to delay name-lookup to instantiation time completly, the Standard distinguishes two types of names: non-dependent names are looked up as soon as the definition of a template is seen. Dependent names on the other hand are only looked up when a template is instantiated. Qualifying foo with this-> or Parent<type> makes it a dependent name and thus forces the compiler to delay name-lookup until the template is instantiated.


Anmelden zum Antworten