Что такое поиск имен в С++? (& GCC правильно?)
У меня возникла проблема в каком-то производственном коде, который я минимизировал до следующего тестового примера:
template<typename T>
void intermediate(T t)
{
func(t); // line 4 ("func not declared in this scope")
}
namespace ns {
struct type {};
}
void func(ns::type const & p); // line 11 ("declared here, later")
void foo(ns::type exit_node)
{
intermediate(exit_node); // line 15 ("required from here")
}
GCC 4.5 компилирует этот штраф. Как с, так и без -std=c++11
, 4.7 и 4.9 вызывают такие сообщения, как:
test.cpp: In instantiation of ‘void intermediate(T) [with T = ns::type]’:
test.cpp:15:27: required from here
test.cpp:4:5: error: ‘func’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
test.cpp:11:6: note: ‘void func(const ns::type&)’ declared here, later in the translation unit
Все три следующие вещи приведут к успешному компиляции файла:
- Переместите
func(ns::type)
в пространство имен ns
(позволяя ADL найти его в ns
)
- Переместите
type
в глобальное пространство имен (позволяя ADL найти его в ::
)
- Избавьтесь от
intermediate
и вызовите func
непосредственно из foo
Итак... что здесь происходит? Является ли законным для GCC отказаться от этой программы? Почему func
найден неквалифицированным поиском в третьем варианте (вызов func
непосредственно из foo
), но не найден неквалифицированным поиском в исходном варианте в момент создания экземпляра?
Ответы
Ответ 1
Общее правило заключается в том, что все, что не в контексте определения шаблона, может быть получено только через ADL. Другими словами, нормальный неквалифицированный поиск выполняется только в контексте определения шаблона.
Поскольку объявление func
не отображается, если intermediate
определено, а func
не находится в пространстве имен, ассоциированном с ns::type
, код плохо сформирован.
Ответ 2
GCC прав. func
можно найти только через ADL, так как это неквалифицированный, зависимый вызов функции. func
объявляется в глобальном пространстве имен, но это не связанное с ним пространство имен ns::type
, а только ns
(поэтому ваш текущий код не работает). Когда вы заменяете intermediate(exit_node)
на прямой вызов func(exit_node)
внутри foo
, то он обнаруживается обычным неквалифицированным поиском.