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

oz1*_*1cz 20 c++ templates base-class dependent-name name-lookup

考虑以下代码:

#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();
}
Run Code Online (Sandbox Code Playgroud)

该代码旨在研究名称查找在C++中的工作方式.

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

N::f
::f
Run Code Online (Sandbox Code Playgroud)

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

Base::f
Base::f
Run Code Online (Sandbox Code Playgroud)

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

Tem*_*Rex 15

g ++符合标准,Visual C++不符合:

14.6.2从属名称[temp.dep]

3在类或类模板的定义中,在类模板或成员的定义点或类模板的实例化期间,在非限定名称查找期间不检查从属基类(14.6.2.1)的范围或成员.

替换f()this->f()将找到基本成员.

  • 完全是@ oz1cz!在参考书C++模板完整指南中有一整段(9.4.2.). (3认同)

Vla*_*cow 6

在函数的函数定义中,g名称f被视为在类外部声明的函数(在类定义中,此名称未声明; f是从属名称).

template <typename T>
class X : public Base<T> {
  public:
    void g() {
        T t;
        f(t);
    }
};
Run Code Online (Sandbox Code Playgroud)

因此编译器使用ADL查找.

但是,如果要编写成员函数的显式调用

class X : public Base<T> {
  public:
    void g() {
        T t;
        this->f(t);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后函数的调用f将被视为基类成员函数的调用.

因此,似乎MS VC++ 2015有一个bug.