Name lookup differences between g++ and MSVS
Asked Answered
C

2

20

Consider this code:

#include <iostream>

namespace N {
    class A {};
    void f(A a) { std::cout << "N::f\n"; }
}

void f(int i) { std::cout << "::f\n"; }

template <typename T>
class Base {
  public:
    void f(T x) { std::cout << "Base::f\n"; }
};


template <typename T>
class X : public Base<T> {
  public:
    void g() {
        T t;
        f(t);
    }
};

int main()
{
    X<N::A> x1;
    x1.g();

    X<int> x2;
    x2.g();
}

The code is intended to investigate how name lookup works in C++.

If I compile this program with GNU C++ (version 6.1.0), it prints:

N::f
::f

But if I compile it with Microsoft Visual Studio 2015, it prints:

Base::f
Base::f

Which is the correct behaviour, and why?

Cowles answered 30/8, 2016 at 12:51 Comment(2)
I don't know the answer to this question per say, but I do know that Microsoft Visual Studio's C++ compiler is often not standard complying. (So my guess is that Microsoft VS is wrong)Phthalein
VS 2015 should be getting really close to being standard though. Clang seems to behave like GCC after a quick check. So without knowing the details I would also assume VS is wrong. Maybe you stumbled over a bug here.Vivianne
A
15

g++ is Standard compliant here, and Visual C++ not:

14.6.2 Dependent names [temp.dep]

3 In the definition of a class or class template, the scope of a dependent base class (14.6.2.1) is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

Replacing f() with this->f() will find the base member.

Aachen answered 30/8, 2016 at 13:40 Comment(2)
Thank you, TemplateRex. I wonder why C++ has this rule. Is it because template specialization may yield a Base class with no f function?Cowles
@Cowles exactly! There is a whole passage (9.4.2.) on this in the reference book C++ Templates the Complete Guide.Aachen
P
6

In the function definition of the function g the name f is considered as a function declared outside the class (within the class definition this name is not declared; f is a dependent name).

template <typename T>
class X : public Base<T> {
  public:
    void g() {
        T t;
        f(t);
    }
};

So the compiler uses the ADL lookup.

However if to write an explicit call of a member function

class X : public Base<T> {
  public:
    void g() {
        T t;
        this->f(t);
    }
};

then the call of the function f will be considered as a call of the member function of the base class..

Thus it seems that MS VC++ 2015 has a bug.

Phrasal answered 30/8, 2016 at 13:6 Comment(5)
Why is f considered a name declared outside the scope of the class? Is that normal behavior and it only falls back into the class scope if nothing can be found outside the class ?Caucasus
@Caucasus It is a specific behavior of template derived classes. I have no at hand the C++ Standard so I can not get the relevant quote.Phrasal
That is interesting. I'll have to do some looking. g++ seems to not even fall back as this fails to compile.Caucasus
@Caucasus It confirms what I wrote. The name f looked outside the class definition (because in the template class definition there is no member with the name f) is not exists.Phrasal
@Caucasus See this question #27178983Phrasal

© 2022 - 2024 — McMap. All rights reserved.