Вопрос о разрешении имен свободных функций в шаблонах C ++ - PullRequest
0 голосов
/ 01 марта 2019

Эта программа работает должным образом:

#include <iostream>

template <typename T>
void output(T t) {
   prt(t);
}

struct It {
   It(int* p) : p(p) {}
   int* p;
};

void prt(It it) {
   std::cout << *(it.p) << std::endl;
}

int main() {
   int val = 12;
   It it(&val);
   output(it);    
   return 0;
}

Когда вы компилируете и выполняете это, она печатает «12», как и должно.Даже если функция prt , требуемая шаблонной функцией output , определена после того, как output , prt видим в точке созданияи, следовательно, все работает.

Программа ниже очень похожа на программу выше, но она не компилируется:

#include <iostream>

template <typename T>
void output(T t) {
   prt(t);
}

void prt(int* p) {
   std::cout << (*p) << std::endl;
}

int main() {
   int val = 12;
   output(&val);
   return 0;
}

Этот код пытается сделать то же самое, что и предыдущийпример, но это не работает в gcc 8.2 с сообщением об ошибке:

     'prt' was not declared in this scope, and no declarations were found by
 argument-dependent lookup at the point of instantiation [-fpermissive]

Единственное, что изменилось, это то, что аргумент, передаваемый output , является встроенным типом, а непользовательский тип.Но я не думаю, что это должно иметь значение для разрешения имен.Итак, мой вопрос: 1) почему второй пример терпит неудачу ?;и 2) почему один пример терпит неудачу, а другой - успешно?

1 Ответ

0 голосов
/ 01 марта 2019

Стандартное правило, которое здесь применяется, находится в [temp.dep.candidate] :

Для вызова функции, где postfix-expression является зависимым именем, функции-кандидаты находятся с использованием обычных правил поиска ([basic.lookup.unqual], [basic.lookup.argdep]) за исключением того, что:

  • Для деталипоиска с использованием поиска без определения имени, только объявления функций из контекста определения шаблона.

  • Для части поиска с использованием связанных пространств имен ([basic.lookup.argdep]),найдены только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания экземпляра шаблона.

В обоих примерах поиск по неквалифицированным именам не находит объявлений prt, посколькуне было таких объявлений до того момента, когда шаблон был определен.Поэтому мы переходим к поиску, зависящему от аргументов, который ищет только в связанных пространствах имен типов аргументов.

Класс It является членом глобального пространства имен, поэтому глобальное пространство имен является единственным связанным пространством имен,и одно объявление видно в этом пространстве имен в контексте создания шаблона.

Тип указателя U* имеет те же связанные пространства имен, что и тип U, а фундаментальный тип вообще не имеет связанных пространств имен.Так как единственный тип аргумента int* - это указатель на фундаментальный тип, нет связанных пространств имен , и зависящий от аргумента поиск не может найти никаких объявлений во второй программе.

Я не могу точно сказать, почему правила были разработаны таким образом, но я предполагаю, что цель состоит в том, что шаблон должен либо использовать определенные объявленные функции, которые он хотел использовать, либо использовать функцию в качестве расширяемой точки настройки, но этипользовательские настройки должны быть тесно связаны с пользовательским типом, с которым они будут работать.В противном случае становится возможным изменить поведение шаблона, который действительно подразумевал использование одной конкретной функции или объявления шаблона функции, обеспечивая лучшую перегрузку для некоторого конкретного случая.Следует признать, что это больше с точки зрения того, когда в контексте определения шаблона есть хотя бы одно объявление, а не когда этот поиск вообще ничего не находит, но тогда мы попадаем в случаи, когда SFINAE рассчитывал на то, что что-то не найдет и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...