[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.