Различия в поиске имен между g++ и 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

Какое поведение правильно и почему?

2 ответа

Решение

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

Таким образом, компилятор использует поиск ADL.

Однако, если написать явный вызов функции-члена

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

тогда вызов функции f будет рассматриваться как вызов функции-члена базового класса.

Таким образом, кажется, что MS VC++ 2015 имеет ошибку.

Другие вопросы по тегам