Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ symbol scope search order different for template and non-template class?

#include <iostream>

void foo()
{
    std::cout << "global foo()" << std::endl;
}

struct A {
    void foo()
    {
        std::cout << "A::foo()" << std::endl;
    }
};

struct B : public A {
    void call()
    {
        foo();
    }
};

int main(int argc, char **argv )
{
    B b;
    b.call();
    return 0;
}

This gives expected result:

A::foo()

However after changing two lines (class B to template):

#include <iostream>

void foo()
{
    std::cout << "global foo()" << std::endl;
}

struct A {
    void foo()
    {
        std::cout << "A::foo()" << std::endl;
    }
};

template <typename T> // change here
struct B : public T {
    void call()
    {
        foo();
    }
};

int main(int argc, char **argv )
{
    B<A> b; // and here
    b.call();
    return 0;
}

I get unexpected result:

global foo()

And using this-> is not an option as I am trying to create a "fallback" mechanism.

like image 886
elmo Avatar asked Apr 20 '12 14:04

elmo


People also ask

What is the difference between class template and template class?

A class template is a template that is used to generate classes whereas a template class is a class that is produced by a template.

What is the difference between template T and template typename T?

There is no difference. typename and class are interchangeable in the declaration of a type template parameter.

What is the difference between function template and class template in C++?

For normal code, you would use a class template when you want to create a class that is parameterised by a type, and a function template when you want to create a function that can operate on many different types.

What is function template and class template?

Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.


1 Answers

What you get is an expected result. This is called "Two-phase name lookup" in the C++ standard.

Names inside templates are divided into two types:

Dependent – names that depend on the template parameters but aren’t declared within the template.

Non-dependent – names that don’t depend on the template parameters, plus the name of the template itself and names declared within it.

When the compiler tries to resolve some name in the code, it first decides whether the name is dependent or not, and the resolution process stems from this distinction. While non-dependent names are resolved "normally" – when the template is defined, the resolution for dependent names happens at the point of the template’s instantiation.

foo(); in B::call in your example is a non-dependent name, so it is resolved to global foo() at the point of template definition.

like image 154
Andrey Avatar answered Sep 16 '22 12:09

Andrey