函数模板显式特化声明中尾随模板参数的推导(无函数参数推导)
Deduction of trailing template-argument in declaration of explicit specializations of function templates (no function arg. deduction)
(这个问题是 评论中讨论的分支。)
[temp.expl.spec]/10 表示 [强调 我的]:
A trailing
template-argument
can be left unspecified in the
template-id
naming an explicit function template specialization provided it can be
deduced from the function argument type. [ Example:
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v);
// explicit specialization for sort(Array<int>&)
// with deduced template-argument of type int
template<> void sort(Array<int>&);
— end example ]
这显然适用于下面示例中 foo(T)
的(完全)显式特化:
#include <iostream>
template <typename T>
void foo(T) { std::cout << "primary\n"; }
template <>
void foo(int) { std::cout << "int\n"; }
// OK ^<int> deduced from template argument deduction
// in this _declaration_, as of [temp.expl.spec]/10
int main()
{
const int a = 42;
foo(a); // int
// OK, <int> deduced from template argument deduction.
}
但是,对于 clang 和 GCC,对于我测试过的所有各种 ISO C++ 版本,这也适用于函数模板中没有函数参数的示例,以及它的类型模板参数仅作为函数模板的 return 类型存在:
#include <iostream>
template <typename T>
T bar() { std::cout << "primary\n"; return 0; }
template <>
int bar() { std::cout << "int\n"; return 42; }
// ^<int> deduced?
int main()
{
(void)bar<int>(); // int
// ^^^ OK, no template argument deduction.
}
我对上面引述中的术语 “演绎” 有点困惑,因为它,afaics,并不是指典型意义上的演绎(称为 site/instantiation) 模板参数推导,而是在专业化声明的上下文中推导。
问题:
- 在 ISO C++ 标准中,尾随模板参数 在具有模板参数的显式函数模板特化声明中仅作为 [=43] =] 类型,实际上可能被省略(推导)?
我认为 [temp.expl.spec]/10 在说 "function argument type" 而不是 "function type" 时用词不当一个函数模板。 (当然,函数参数类型可能不止一种。)
不同的上下文指定不同的依赖类型集 (P
) 和指定的(通常是非依赖的)类型集 (A
) 用于模板参数推导,如小节 [temp.deduct.call], [temp.deduct.funcaddr], [temp.deduct.conv], [temp.deduct.partial], and [temp.deduct.decl].
最熟悉的可能是第一个,[temp.deduct.call]:调用函数模板时,函数参数类型为P
,参数表达式的类型为A
,但return类型的函数模板不参与
最后一个,[temp.deduct.decl],涵盖了函数模板显式特化的匹配(如您的示例)、函数模板的显式实例化以及函数特定特化的友元声明模板。对于这些情况,整个函数类型为 P
和 A
。由于函数类型算作由 return 类型和参数类型形成的 "compound type",类似于指针类型 T*
由类型 T
形成的方式,这允许推导在参数类型中 return 类型 and/or 中出现的模板参数的数量。
(这个问题是
[temp.expl.spec]/10 表示 [强调 我的]:
A trailing template-argument can be left unspecified in the template-id naming an explicit function template specialization provided it can be deduced from the function argument type. [ Example:
template<class T> class Array { /* ... */ }; template<class T> void sort(Array<T>& v); // explicit specialization for sort(Array<int>&) // with deduced template-argument of type int template<> void sort(Array<int>&);
— end example ]
这显然适用于下面示例中 foo(T)
的(完全)显式特化:
#include <iostream>
template <typename T>
void foo(T) { std::cout << "primary\n"; }
template <>
void foo(int) { std::cout << "int\n"; }
// OK ^<int> deduced from template argument deduction
// in this _declaration_, as of [temp.expl.spec]/10
int main()
{
const int a = 42;
foo(a); // int
// OK, <int> deduced from template argument deduction.
}
但是,对于 clang 和 GCC,对于我测试过的所有各种 ISO C++ 版本,这也适用于函数模板中没有函数参数的示例,以及它的类型模板参数仅作为函数模板的 return 类型存在:
#include <iostream>
template <typename T>
T bar() { std::cout << "primary\n"; return 0; }
template <>
int bar() { std::cout << "int\n"; return 42; }
// ^<int> deduced?
int main()
{
(void)bar<int>(); // int
// ^^^ OK, no template argument deduction.
}
我对上面引述中的术语 “演绎” 有点困惑,因为它,afaics,并不是指典型意义上的演绎(称为 site/instantiation) 模板参数推导,而是在专业化声明的上下文中推导。
问题:
- 在 ISO C++ 标准中,尾随模板参数 在具有模板参数的显式函数模板特化声明中仅作为 [=43] =] 类型,实际上可能被省略(推导)?
我认为 [temp.expl.spec]/10 在说 "function argument type" 而不是 "function type" 时用词不当一个函数模板。 (当然,函数参数类型可能不止一种。)
不同的上下文指定不同的依赖类型集 (P
) 和指定的(通常是非依赖的)类型集 (A
) 用于模板参数推导,如小节 [temp.deduct.call], [temp.deduct.funcaddr], [temp.deduct.conv], [temp.deduct.partial], and [temp.deduct.decl].
最熟悉的可能是第一个,[temp.deduct.call]:调用函数模板时,函数参数类型为P
,参数表达式的类型为A
,但return类型的函数模板不参与
最后一个,[temp.deduct.decl],涵盖了函数模板显式特化的匹配(如您的示例)、函数模板的显式实例化以及函数特定特化的友元声明模板。对于这些情况,整个函数类型为 P
和 A
。由于函数类型算作由 return 类型和参数类型形成的 "compound type",类似于指针类型 T*
由类型 T
形成的方式,这允许推导在参数类型中 return 类型 and/or 中出现的模板参数的数量。