【问题标题】:Function overloading: empty parameter list vs parameter pack函数重载:空参数列表 vs 参数包
【发布时间】: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,这是为什么呢?

【问题讨论】:

  • 你必须在文本中用单引号转义&lt;&gt;,否则它是不可见的,为你解决了这个问题,但不确定我是否错过了一些
  • #1 不是专业吗?
  • @freakish 不是。这是一个主要模板。

标签: c++ templates language-lawyer variadic-templates overload-resolution


【解决方案1】:

编译器是正确的。 #1#2 更专业。


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

使用结果类型 PA,然后进行推导 在 [temp.deduct.type] 中描述。如果P 是函数参数包, 参数模板的每个剩余参数类型的类型A 与函数的 declarator-id 的类型 P 进行比较 参数包。每个比较推导出模板参数 模板参数包中的后续位置由 函数参数包。类似地,如果 A 从 函数参数包,它与每个剩余参数进行比较 参数模板的类型。如果给定的扣除成功 类型,参数模板中的类型至少被认为是 与参数模板中的类型一样特化。

当参数模板为#1 且参数模板为#2 时,将#2 中的declarator-id Args(这是一个类型)与每个#1 中的剩余参数(没有)。因此,#2 至少和#1 一样专业。

当参数模板为#2 且参数模板为#1 时,将#2 中的declarator-id Args(它是一个类型)与每个#1 中的剩余参数(没有)。因此,#1 至少和#2 一样专业。

似乎模棱两可,对吧?现在我们有决胜局了,[temp.deduct.partial]/11:

如果考虑到上述情况,函数模板F至少为 专门作为函数模板G 反之亦然,如果G 有一个 F 没有对应的尾随参数包 参数,如果F 没有尾随参数包,则 FG 更专业。

显然,#1#2 更专业。

【讨论】:

    猜你喜欢
    • 2015-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2013-03-06
    • 1970-01-01
    相关资源
    最近更新 更多