函数重载:空参数列表与参数包

Function overloading: empty parameter list vs parameter pack

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。

但是,标准中的部分排序规则说:

If the parameter-declaration corresponding to Pi is a function parameter pack, then the type of its declarator-id is compared with each remaining parameter type in the parameter-type-list of A. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. During partial ordering, if Ai was originally a function parameter pack:

  • (10.1) if P does not contain a function parameter type corresponding to Ai then Ai is ignored;

  • (10.2) otherwise, if Pi is not a function parameter pack, template argument deduction fails.

当我们从#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#2 更专业。


部分排序模板参数包的规则在[temp.deduct.partial]/8中指定:

Using the resulting types P and A, the deduction is then done as described in [temp.deduct.type]. If P is a function parameter pack, the type A of each remaining parameter type of the argument template is compared with the type P of the declarator-id of the function parameter pack. Each comparison deduces template arguments for subsequent positions in the template parameter packs expanded by the function parameter pack. Similarly, if A was transformed from a function parameter pack, it is compared with each remaining parameter type of the parameter template. If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.

当参数模板为#1且参数模板为#2时,declarator-id Args(这是一个类型) 来自 #2#1 中的每个剩余参数(有 none)进行比较。因此,#2 至少与 #1.

一样专业

当参数模板为#2且参数模板为#1时,declarator-id Args(这是一个类型) 来自 #2#1 中的每个剩余参数(有 none)进行比较。因此,#1 至少与 #2.

一样专业

好像很暧昧吧?现在我们有了决胜局,[temp.deduct.partial]/11:

If, after considering the above, function template F is at least as specialized as function template G and vice-versa, and if G has a trailing parameter pack for which F does not have a corresponding parameter, and if F does not have a trailing parameter pack, then F is more specialized than G.

显然,#1#2 更专业。