c++ – Why is it necessary to specify the name of the base class when calling an inherited function, if there is only one way to resolve this call?

Question:

What specifically in this case prevents you from accessing the base class function directly by name without specifying the class? If protected forbids any other call to a_func() except through A<​T​> from a class inherited from A<​T​> , then what kind of ambiguity could (potentially) arise if A<​T​> was 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 you uncomment the first variant of b_func(), 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 the 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 performed at the template parsing stage, for dependent names – when the template is instantiated. This contributes to the detection of 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 functions b_func() and a_func() 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, the global space). The name lookup in the base structure will not be performed 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 don't implement two-phase name lookup.

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

Scroll to Top