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

Различное поведение для квалифицированного и неквалифицированного поиска имени для шаблона

Как должен вести себя этот код? Он вызывает общую функцию, игнорирующую мою перегрузку, если я использую квалифицированное имя в функции call_read(); и он сначала вызывает перегрузку, а затем общую версию, если я использую неквалифицированное имя. Какая разница? Это ошибка в GCC?

#include <iostream>

struct info1 {};
struct info2 {};

template<class T> void read(T& x)
{
   std::cout << "generic" << std::endl;
}

template<class T> void call_read(T& x)
{
   ::read(x); // if I replace ::read(x) with read(x) the overload is called
}

void read(info1& x)
{
   std::cout << "overload" << std::endl;
}

int main()
{
   info1 x;
   info2 y;
   call_read(x);
   call_read(y);
}

Я также заметил, что он работает по-разному для фундаментальных типов. См. Ниже приведенный ниже код

#include <iostream>

typedef struct info1 {};
typedef struct info2 {};
typedef int info3;
typedef double info4;

template<class T> void read(T x)
{
    std::cout << "generic" << std::endl;
}

template<class T> void call_read(T x)
{
    read(x);
}

void read(info1 x)
{
    std::cout << "overload" << std::endl;
}
void read(info3 x)
{
    std::cout << "overload" << std::endl;
}

int main()
{
    call_read(info1());
    call_read(info2());
    call_read(info3());
    call_read(info4());
}

Предполагается, что функция перегружать дважды, но это не так. См. Результат здесь http://codepad.org/iFOOFD52

4b9b3361

Ответ 1

То, что вы наблюдаете, представляет собой суперпозицию поиска по двухфазному имени и поиска по зависимым от аргументов.

Посмотрим, что говорит стандарт (С++ 03). [Temp.dep]:

[...] В выражении вида:

postfix-expression ( expression-listopt )

где постфиксное выражение является идентификатором, идентификатор обозначает зависимое имя тогда и только тогда, когда любое из выражений в списке выражений является зависимым от типа выражением (14.6.2.2).

Это означает, что как в read, так и ::read, read является зависимым именем, потому что x зависит от типа. Это означает, что он разрешился в момент создания экземпляра. Посмотрим, какие правила для этого [temp.dep.candidate]:

Для вызова функции, который зависит от параметра шаблона, если имя функции является неквалифицированным идентификатором, но не идентификатором шаблона, функции-кандидаты определяются с использованием обычных правил поиска (3.4.1, 3.4.2), за исключением что:

- Для части поиска, использующей поиск неквалифицированного имени (3.4.1), найдены только объявления функций с внешней связью из контекста определения .

Поэтому для случая ::read рассматриваются только функции, объявленные до определения шаблона. Но:

- Для части поиска с использованием связанных пространств имен (3.4.2) только объявления функций с внешней привязкой, найденные либо в контексте определения, либо в шаблоне контекст контекста.

для неквалифицированной read рассматриваются обе функции, видимые при определении шаблона и создании шаблона.

Ответ 2

Да, это ожидаемое поведение. В первом случае (:: read) вы эффектно отключите ADL (зависимый от аргумента поиск), который ограничивает поиск имени теми вещами, которые были объявлены в глобальной области до использования вами чтения. Если вы удалите:: ADL будет ударять, что может разрешить функции, которые вы объявили после вашего шаблона функции.

Изменить: И поскольку для таких фундаментальных типов, как int и double нет ADL, это объясняет ваше второе наблюдение.

Ответ 3

Компилятор всегда будет вызывать метод, который наиболее соответствует вашему звонку. Здесь вы вызываете:

read(T& x) [with T = info1]

Таким образом, компилятор предпочтет перегрузку, поскольку он точно соответствует вызову. Это в логике специализированных шаблонов, что позволяет утверждать, что если существует перегруженная функция, которая лучше соответствует вашему вызову, то этот будет использоваться.

Во второй части вопроса, касающемся разницы при использовании полностью квалифицированных и неквалифицированных имен, это происходит из-за того, что полностью квалифицированное имя не зависит ни от чего другого и поэтому разрешено к первому совпадению (здесь объявление шаблона).