【发布时间】:2019-09-19 08:11:17
【问题描述】:
template <typename T>
void call(T) { //#1
std::cout << "1" << std::endl;
}
template <typename T, typename...Args>
void call(T, Args...) { //#2
std::cout << "2" << std::endl;
}
当我这样调用函数时
call(10);
GCC、Clang 和 MSVC 都使用 #1。
但是,标准中的偏序规则说:
如果Pi对应的parameter-declaration是一个函数参数包,则将其declarator-id的类型与parameter-type-list of A。每次比较都会推导出模板参数包中由函数参数包扩展的模板参数包中的后续位置的模板参数。偏序时,如果 Ai 原本是一个函数参数包:
(10.1) 如果 P 不包含对应于 Ai 的函数参数类型,则忽略 Ai;
(10.2) 否则,如果 Pi 不是函数参数包,则模板参数推导失败。
当我们从#2 推导出#1 时,将T, Args... 作为A,T 作为P,P 不包含对应于Args... 的模板参数。 Args... 被忽略,所以#1 可以成功地从#2 推导出来。
然后从#1推导出#2,T为A,T, Args...为P,也成功得到T = T, Args... = {}。
因此,根据偏序规则,当调用call(10)时,编译器应该会给出模棱两可的错误,但实际上所有编译器都调用了#1,这是为什么呢?
【问题讨论】:
-
你必须在文本中用单引号转义
<>,否则它是不可见的,为你解决了这个问题,但不确定我是否错过了一些 -
#1 不是专业吗?
-
@freakish 不是。这是一个主要模板。
标签: c++ templates language-lawyer variadic-templates overload-resolution