g++ 和 MSVS 之间的名称查找差异

Name lookup differences between g++ and MSVS

考虑这段代码:

#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();
}

该代码旨在研究名称查找在 C++ 中的工作原理。

如果我用 GNU C++(版本 6.1.0)编译这个程序,它会打印:

N::f
::f

但是如果我用 Microsoft Visual Studio 2015 编译它,它会打印:

Base::f
Base::f

哪种行为是正确的,为什么?

在函数 g 的函数定义中,名称 f 被视为在 class 之外声明的函数(在 class 定义中,此名称不是已声明;f 是从属名称)。

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

因此编译器使用 ADL 查找。

但是如果写一个成员函数的显式调用

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

那么函数f的调用会被认为是基class的成员函数的调用..

因此,MS VC++ 2015 似乎有一个错误。

g++ 在这里是标准兼容的,而 Visual C++ 不是:

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.

f() 替换为 this->f() 将找到基础成员。