Рассмотрим этот пример кода
template <typename T> struct S { T t; };
template <class T> void foo(const S<T> &v)
{
bar(v.t);
}
namespace N
{
struct A {};
}
void bar(const N::A &a) {}
int main()
{
S<N::A> a;
foo(a);
}
Код не может скомпилироваться в GCC и Clang, поскольку ни обычный поиск, ни ADL не могут разрешить вызов bar
из foo
.Это вполне ожидаемо, поскольку список связанных пространств имен для вызова bar
просто N
.Глобальное пространство имен не включено, глобальное bar
не найдено.Все как и должно быть.
Однако, если я изменю его на
template <typename T> struct S { T t; };
template <class T> void foo(const S<T> &v)
{
+v.t;
}
namespace N
{
struct A {};
}
void operator +(const N::A& a) {}
int main()
{
S<N::A> a;
foo(a);
}
, он неожиданно начнет успешно компилироваться в GCC.(Между тем Clang отклоняет обе версии кода).
Похоже, что во второй (основанной на операторах) версии кода GCC рассматривает глобальное пространство имен как связанное пространство имен для ADL.
Если в последней версии кода я изменю вызов на
template <class T> void foo(const S<T> &v)
{
operator +(v.t);
}
, он снова не сможет скомпилироваться в GCC.Таким образом, похоже, что какая-то особая обработка применяется к операторам в выражениях , особенно к нотации, но не к функции-вызова , к записи.
Это стандарт поведения?Кажется, я не нахожу его в тексте документа (в поисках «связанного пространства имен»), хотя я смутно помню, что читал что-то об этой особенности GCC.