В следующем коде C++ заполнитель шаблона в аргументе функции fun1 и в возвращаемом типе функции ret1 не компилируется:
template <typename T = int>
class type {
T data;
};
void fun1(type arg); // Error: template placeholder not permitted in this context
void fun2(type<> arg); // Ok
void fun3(type<int> arg); // Ok
type ret1(); // Error: Deduced class type 'type' in function return type
type<> ret2(); // Ok
type<int> ret3(); // Ok
int main() {
type var1; // Ok!!!!!!
type<> var2; // Ok
type<int> var3; // Ok
}
Но var1 это нормально.
var1 компилируется, а fun1 и ret1 нет?




var1 выигрывает от CTAD, где все нестандартные аргументы шаблона (т. е. ни одного) могут быть выведены из инициализации. Однако оба объявления функций не являются кандидатами для CTAD, поэтому список аргументов шаблона должен быть предоставлен, даже если этот список пуст.
Вычет за шаблоны классов
Неявно генерируемые руководства по дедукции
Когда в приведении в стиле функции или в объявлении переменной спецификатор типа состоит исключительно из имени шаблона первичного класса C (т. е. нет сопутствующего списка аргументов шаблона), кандидаты для вывода формируются следующим образом: ...
(выделение добавлено)
type var1; использует вывод аргумента шаблона класса (CTAD), который возможен, начиная с C++ 17, и выводит аргументы шаблона из инициализатора переменной (здесь пустой список аргументов).
Это невозможно в объявлении функции, потому что нет инициализатора, из которого можно вывести аргументы шаблона.
В частности, для параметра функции не будет никакого возможного источника для определения аргументов шаблона (за исключением случаев, когда такая функция будет рассматриваться как шаблон, аналогичный сокращенным шаблонам функций C++20).
Для возвращаемого типа его можно было указать аналогично тому, как работает тип возвращаемого значения auto, но это просто не было сделано при внедрении CTAD.