G CC содержит ошибку.
Поиск имени всегда выполняется для имен шаблонов, появляющихся перед <
, даже если рассматриваемое имя является именем, объявленным в (другом, явной специализации) или явное создание экземпляра) объявление.
Поскольку имя operator==
в объявлении друга является неквалифицированным именем и подлежит поиску имени в шаблоне, применяются правила двухфазного поиска имени. В этом контексте operator==
не является зависимым именем (оно не является частью вызова функции, поэтому ADL не применяется), поэтому имя ищется и связывается в той точке, где оно появляется (см. Параграф [temp.nondep] 1). Ваш пример неверно сформирован, потому что этот поиск имени не находит объявления operator==
.
. Я ожидаю, что G CC принимает это в режиме C ++ 20 из-за P0846R0 , что позволяет (например) operator==<T>(a, b)
использоваться в шаблоне, даже если не видно предварительного объявления operator==
в качестве шаблона.
Вот еще более интересный тестовый пример:
template <typename T> struct Foo;
#ifdef WRONG_DECL
template <typename T> bool operator==(Foo<T> lhs, int); // #1
#endif
template <typename T> struct Foo {
friend bool operator==<T>(Foo<T> lhs, float); // #2
};
template <typename T> bool operator==(Foo<T> lhs, float); // #3
Foo<int> f;
С -DWRONG_DECL
, G CC и Clang согласны с тем, что эта программа некорректна: неквалифицированный поиск объявления друга № 2 в контексте определения шаблона находит объявление № 1, которое не соответствует конкретный друг Foo<int>
. Декларация № 3 даже не рассматривается, потому что неквалифицированный поиск в шаблоне не находит ее.
С -UWRONG_DECL
, G CC (в C ++ 17 и более ранних версиях) и Clang согласны с тем, что эта программа неправильно сформирован по другой причине: неквалифицированный поиск для operator==
в строке # 2 ничего не находит.
Но с -UWRONG_DECL
G CC в режиме C ++ 20, кажется, решает, что все в порядке этот неквалифицированный поиск для operator==
в # 2 завершается неудачно (предположительно из-за P0846R0), а затем, кажется, восстанавливает поиск из контекста создания шаблона, теперь находя # 3, в нарушение обычного правила поиска двухфазного имени для шаблонов.