GCC и ADL для операторов в выражениях - PullRequest
0 голосов
/ 27 сентября 2018

Рассмотрим этот пример кода

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.

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Это сообщение об ошибке, похоже, связано Ошибка 70099 .Пространство имен оператора не учитывается при поиске.

Оператор является зависимым именем [temp.dep]/1.3:

Если операнд оператора является выражением, зависящим от типа,оператор также обозначает зависимое имя.Такие имена не связаны и ищутся в точке создания шаблона (17.6.4.1) как в контексте определения шаблона, так и в контексте точки создания

и [temp.dep.res]

При разрешении зависимых имен учитываются имена из следующих источников: 1. Объявления, видимые в точке определения шаблона.2. Объявления из пространств имен, связанных с типами аргументов функции, как из контекста экземпляра (17.6.4.1), так и из контекста определения.

, а объявление оператора не входит ни в один из контекстовни в связанных пространствах имен N::A.

0 голосов
/ 27 сентября 2018

Это ошибка gcc 51577 .Второй тестовый пример в значительной степени соответствует вашему примеру кода.

Не существует специального правила для поиска операторов, которое будет выглядеть в глобальном пространстве имен. [over.match.oper] / 3 имеет:

Набор кандидатов, не являющихся членами, является результатом неквалифицированного поиска operator@ в контексте выраженияв соответствии с обычными правилами поиска имен в вызовах неквалифицированных функций ([basic.lookup.argdep]), за исключением того, что все функции-члены игнорируются.

Обычные правила поиска имен в вызовах неквалифицированных функций невключить глобальное пространство имен: [basic.lookup.argdep] / 2 :

Если T является типом класса (включая объединения), его ассоциированными классами являются: класссам;класс, членом которого он является, если таковой имеется;и его прямые и косвенные базовые классы.Его связанные пространства имен являются самыми внутренними вмещающими пространствами имен связанных с ними классов.

N::A является типом класса, связанный с ним класс сам по себе, его связанные пространства имен являются внутренними включающими пространствами имен, который просто N, а не ::.

...