Поиск зависимых имен, зависящих от аргументов

В этом описании на cppreference.com говорится, что

Поиск зависимого имени, используемого в шаблоне, откладывается до тех пор, пока не станут известны аргументы шаблона, когда [...] ADL проверяет объявления функций с внешней связью, которые видны либо из контекст определения шаблона или контекст создания шаблона.

В противоположность этому следующий фрагмент кода отлично компилируется с помощью трех компиляторов (MSVC, clang, gcc):

template <class T>
void CallFoo ()
{
    Foo (T ());
}


class Apple {};


int main ()
{
    CallFoo<Apple> ();
}


static void Foo (Apple)
{
}

Foo - это зависимое имя в CallFoo: оно зависит от аргумента шаблона T. Но функция Foo найдена компилятором, несмотря на нарушение двух из приведенных выше правил.

  • Объявление Foo не видно ни из определения, ни из экземпляра CallFoo, потому что оно ниже обоих.
  • Foo имеет внутреннюю связь.

Маловероятно, что во всех трех компиляторах есть ошибка. Возможно, я что-то неправильно понял. Не могли бы вы подробнее рассказать об этом?


person Dr. Gut    schedule 26.08.2019    source источник
comment
У меня есть аналогичный вопрос с добавлением constexpr. См. здесь,   -  person Dr. Gut    schedule 26.08.2019
comment
В N4713 не упоминается внешняя связь относительно поиска имени, зависящего от аргумента. Думаю, вы обнаружили на сайте cppreference.com пустую болтовню.   -  person Eljay    schedule 26.08.2019
comment
Разве он не сформирован, не требует диагностики? (так что все компиляторы правы :)). Для реализации, я думаю, они используют и file в качестве экземпляра, поэтому они его нашли.   -  person Jarod42    schedule 26.08.2019
comment
Я не знаю, сработает ли какое-то другое правило, но использование анонимного пространства имен (которое также должно сделать связь внутренней?) приводит к сбою, независимо от того, где вы его поместили (после определения Apple, конечно).   -  person ustulation    schedule 27.08.2019
comment
@Eljay пахнет CWG1258.   -  person Language Lawyer    schedule 27.08.2019
comment
Удаленный ответ Натана Оливера, кажется, отвечает на вопрос (для C ++ 17); не уверен, почему он удален   -  person M.M    schedule 27.08.2019
comment
@ M.M: Извините, я не смог его увидеть (через мобильный интерфейс).   -  person Davis Herring    schedule 27.08.2019


Ответы (1)


В C ++ 03 члены анонимных пространств имен могут иметь внешнюю связь, несмотря на то, что они не именуются в других единицах перевода. Поэтому было сочтено допустимым исключать фактические static функции из зависимого ADL. В C ++ 11 анонимные пространства имен налагают внутреннюю связь, поэтому ограничение стало необоснованным. Однако, несмотря на то, что реализации, использующие новое поведение, и проблема, зарегистрированная сразу же в 2011 году (как отмечено в комментариях), формулировка оставалась в двух местах до N4810 в марте 2019 г.

Что касается размещения функции, то это артефакт функций, имеющих несколько точек создания, включая конец любой единицы трансляции, которая их инстанцирует (с небольшими изменениями для модулей в C ++ 20); если создание экземпляра шаблона функции дает разные результаты для разных вариантов, программа плохо сформирована, диагностика не требуется (как также отмечено в комментариях).

person Davis Herring    schedule 27.08.2019
comment
для разных вариантов - вы имели в виду разные точки создания? Неправильно ли составлен мой пример? В CallFoo Foo не видно. В конце файла это. - person Dr. Gut; 30.08.2019
comment
@ Доктор Гут: Да, вот какие здесь ссылки на «выбор». Да, этот код является плохо сформированным отчетом о недоставке, потому что результат разрешения перегрузки зависит от точки создания экземпляра (и потому что более точное соответствие доступен). - person Davis Herring; 30.08.2019