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()将找到基本成员.
在函数的函数定义中,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.