Когда имя шаблона используется в качестве вызываемой функции, при выводе аргумента шаблона используются только аргументы функции и сигнатура функции шаблона, а не тело функции.
Одна из причин, по которой это правило будет трудно изменить в Стандарте, заключается в том, как все работает, если имя перегружено. Более полная картина есть:
Поиск имени находит набор функций и шаблонов функций.
Для каждого шаблона функции в наборе аргументы шаблона определяются из явных аргументов шаблона, дедукции и / или аргументов шаблона по умолчанию. Если вычет не удался или если замена определенных аргументов шаблона в тип функции делает что-то недопустимое, шаблон функции просто отбрасывается из набора перегрузки как нежизнеспособный.
Для каждой сигнатуры функции (будь то из шаблона или нет) выполняется проверка на соответствие параметров функции и аргументов функции. Если нет, функция является нежизнеспособной и отбрасывается из набора перегрузки.
Разрешение перегрузки сравнивает остальные жизнеспособные функции. Для большей части процесса типы функций из шаблонов обрабатываются так же, как не шаблонные функции, но есть несколько окончательных правил разрыва связей, специфичных для специализаций шаблонов функций.
Если разрешение перегрузки выбрало специализацию шаблона функции, и контекст является тем, для которого требуется определение функции, то для создания этого определения также создается тело функции. Если подстановка параметров аргументов шаблона в тело функции делает что-то недопустимое, программа некорректна.
Таким образом, здесь проводится различие между тем, когда и когда создается экземпляр типа функции шаблона функции, и когда создается экземпляр тела функции, и результатами использования недопустимого параметра шаблона в обоих случаях. Вывод из тела функции запутает это.
Но есть и другие ситуации, когда параметр шаблона в типе возврата шаблона функции может быть вовлечен в вывод аргумента шаблона. (Этот список может быть не исчерпывающим.)
Если указатель на функцию или ссылка на функцию инициализируется из имени шаблона функции (или его адреса для регистра указателя), возвращаемые типы участвуют в выводе аргумента шаблона:
template <typename TT>
TT f();
unsigned int (&func_ptr)() = f; // TT deduced as unsigned int
int g(double (*)());
int g_of_f = g(f); // TT deduced as double
Класс или шаблон класса могут иметь шаблон функции преобразования. Тогда некоторые использования выражения с этим типом класса могут неявно использовать этот шаблон, что требует вывода аргументов шаблона в его возвращаемом типе (который также следует за ключевым словом operator
в его объявлениях).
class A {
public:
template <typename TT>
operator std::shared_ptr<TT>() const;
};
std::shared_ptr<int> p = A{}; // TT deduced as int
Также обратите внимание, что функция или шаблон функции, использующий «тип заполнителя» в качестве своего возвращаемого типа (возвращаемый тип содержит ключевое слово auto
), действительно выводит свой возвращаемый тип из операторов return
тела (которые не пропускаются, потому что "if constexpr
"). Хотя функция без заголовка шаблона - это всего лишь одна функция с одним конкретным типом, а не шаблон функции, и этот вывод является отдельным шагом от любых выводов аргументов шаблона.
auto retBool(bool a) {
return true; // return type is bool
}
template <typename T>
constexpr const auto* constify(T* ptr) {
return ptr; // return type is const T* (T* if T is already const)
}