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

时间:2016-08-30 12:51:26

标签: c++ templates base-class name-lookup dependent-name

考虑以下代码:

#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

哪种行为正确,为什么?

2 个答案:

答案 0 :(得分:15)

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

  

14.6.2从属名称[temp.dep]

     

3在类或类模板的定义中,的范围   在不合格的情况下,不检查依赖基类(14.6.2.1)   名称查找或者在类模板的定义点或   成员或在类模板或成员的实例化期间。

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

答案 1 :(得分:6)

在函数String fragment = getIntent.getStringExtra("fragment"); // Do something to load correct fragment 的函数定义中,名称g被视为在类外声明的函数(在类定义中,此名称未声明; f是从属名称)。

f

因此编译器使用ADL查找。

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

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

然后函数class X : public Base<T> { public: void g() { T t; this->f(t); } }; 的调用将被视为对基类的成员函数的调用。

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