Подтвердить что ты не робот

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

Код предназначен для исследования того, как работает поиск имени на С++.

Если я скомпилирую эту программу с помощью GNU С++ (версия 6.1.0), она печатает:

N::f
::f

Но если я скомпилирую его с Microsoft Visual Studio 2015, он печатает:

Base::f
Base::f

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

4b9b3361

Ответ 1

g++ здесь стандартно совместим, а Visual С++ не:

14.6.2 Зависимые имена [temp.dep]

3 В определении шаблона класса или класса область действия зависимый базовый класс (14.6.2.1) не рассматривается при неквалифицированных поиск имени либо в точке определения шаблона класса, либо член или во время создания шаблона или члена класса.

Замена f() на this->f() найдет базовый элемент.

Ответ 2

В определении функции функции 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 VС++ 2015 имеет ошибку.