c++ – Why do you need to specify the name of the base class when accessing an inherited function if there is only one way to resolve this call?

Question:

What exactly in this case prevents you from accessing the function of the base class directly by name without specifying the class? If protected prohibits any other call to a_func() except through A<​T​> from the class inherited from A<​T​> , then what kind of ambiguity (potentially) could arise if A<​T​> not specified when calling a_func() ?

template<typename T>
struct A {
protected:
    static int a_func() { return 42; }
};

template<typename T>
struct B : A<T> {
//  static int b_func() { return a_func(); }       // Почему это не компилируется?
    static int b_func() { return A<T>::a_func(); } // Зачем требуется указывать A<T>?
};

int main() {
    std::cout << B<void>::b_func() << std::endl;
}

If we uncomment the first b_func () option, then GCC 4.9.2 swears like this:

error: there are no arguments to ‘a_func’ that depend on a template parameter,
so a declaration of ‘a_func’ must be available [-fpermissive]

Answer:

This is an example of a so-called two-stage name lookup. G ++ has implemented it since version 3.4. Its peculiarity lies in the fact that the search is divided into two stages: for all names that do not depend on the template argument, the search is carried out at the stage of template parsing, for dependent names – when the template is instantiated. This helps to identify errors at an earlier stage, i.e. without waiting for the template to be instantiated.

From the standard :

When looking for the declaration of a name used in a template definition, the usual lookup rules (3.4.1, 3.4.2) are used for non-dependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known (14.6.2)

In code

static int b_func() { return a_func(); } 

the b_func() and a_func() functions are not used in a dependent context (that is, they do not depend on the type of the template argument), so the compiler will look in the surrounding namespace (in this case, it is the global namespace). The name will not be searched in the underlying structure because it is dependent.

To solve this problem, you can use the a_func() function in a dependent context, for example, using the this (not suitable in a static context), or using A<T>:: or using A<T>::a_func();

Some compilers will compile this example without errors because they do not implement two-phase lookup.

Read more: 12.7.2 Name Lookup, Templates, and Accessing Members of Base Classes

Scroll to Top