Шаблонно-зависимое разрешение имен не должно находить объявления без связи?
В стандарте C++ [temp.point] написано:
Контекст создания выражения, который зависит от аргументов шаблона, представляет собой набор объявлений с внешней связью, объявленных до момента создания специализации шаблона в том же модуле перевода.
Затем в [temp.dep.candidate]:
Для части поиска с использованием связанных пространств имен ([basic.lookup.argdep]) обнаруживаются только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания экземпляра шаблона.
Означает ли это, что следующий код должен дать сбой:
namespace A{
struct S{};
}
template<class T>
void g(T a){
f(a); //f will be found by argument dependent lookup
}
namespace A{
static void f(S); //but f doesn't have external linkage
}
void test(A::S i){
g(i);
}
//point of instantiation of g
//A::f(S) doesn't have external linkage
//=> so it's not in the instantiation context of template g ??
Этот код на самом деле компилируется, так что означает этот стандартный абзац?
1 ответ
Это дефект в стандарте. Первоначально рассмотрены в основной проблеме 561, где комитет решил, что
Примечания от апрельской встречи 2006 года:
Группа пришла к согласию [...], что функции внутренней связи должны быть найдены при поиске (хотя они могут привести к ошибкам, если они выбраны разрешением перегрузки).
К сожалению, соответствующее исправление было недостаточным, как описано в основной проблеме 1258:
C++ 11 расширил правила поиска для вызовов зависимых функций (17.7.4.2 [temp.dep.candidate] параграф 1 bullet 2), чтобы включить функции с внутренней связью; ранее рассматривались только функции с внешней связью. Однако в пункте 6 пункта 17.7.4.1 [temp.point] все еще говорится:
Контекст создания выражения, который зависит от аргументов шаблона, представляет собой набор объявлений с внешней связью, объявленных до момента создания специализации шаблона в том же модуле перевода.
Предположительно эта формулировка была упущена из виду и должна быть приведена в соответствие с новой спецификацией.
То есть предыдущая формулировка вашего второго цитируемого абзаца была
Для части поиска, использующей связанные пространства имен (3.4.2), найдены только объявления функций с внешней связью, найденные либо в контексте определения шаблона, либо в контексте создания шаблона.
... который был изменен для C++11, но это изменение пропустило вашу первую цитату, что сделало его довольно бессмысленным. Смысл в том, что функции с внутренней связью не различаются.