c++ - 具有两个参数包的函数模板重载解析
问题描述
考虑以下代码:
#include<iostream>
template<class..., class... T>
int f(T...) { return 1; }
template<class... T>
int f(T...) { return 2; }
int main()
{
std::cout << f(1);
}
它在 gcc 8.2 上编译和打印1
,但由于调用f(1)
不明确而无法在 clang 7 上编译。
如果调用被f()
两个编译器替换,则编译失败,声称调用不明确。
如果参数包class... T
被一个简单的参数class T
(和T...
)替换T
,两个编译器也声称有歧义。
在第一个示例中,哪个编译器符合标准?我想这归结为函数模板的特定部分排序规则,或者以这种方式使用双参数包是否已经不正确?
编辑:
我的理解是双包本身不是格式错误的,因为如果第二个包可以从函数参数中推导出来,我阅读中的 [temp.param] 17.1/15 似乎明确允许这样做,这似乎是因为T...
函数参数包。
也可以显式指定第一个参数包的参数,但不是第二个参数包,因此并不总是(在模板参数推导之后)至少一个参数包为空。我不确定这是否会使程序格式错误,因为我不知道在这种情况下如何阅读例如 [temp.res] 17.7/8.3。
gcc 和 clang 似乎都可以使用双参数包本身,例如,当删除第二个函数模板重载时,编译器都会 print 1
。但这可能是格式不正确,不需要诊断的情况。
此外,我假设通过类模板参数推导,可变参数类模板可以定义可变参数构造函数模板,这意味着类似于我的双参数包示例的构造函数候选者,据我所知,相同的重载决议和模板参数推导需要放在那个语境下。这个问题是由另一个具有这种设置的问题引起的:Variadic class template deduction failed with gcc 8.2, compiles with clang and msvc 另请参阅:Deduction guides and variadic class templates with variadic template constructors - mismatched argument pack lengths
现在,我还找到了Deduction guide and variadic templates这个问题的答案,我认为这意味着 gcc 是错误的,并且该调用应该被认为是模棱两可的,但我想验证它是否同样适用于此。我也欢迎更详细的推理,因为函数模板部分排序规则对我来说似乎很不清楚。
解决方案
这里有两个问题。
首先,[temp.deduct.partial]/12(我也引用了这个例子,因为它与你的相似)说:
在大多数情况下,如果并非所有模板参数都有值,则推导失败,但出于偏序目的,模板参数可能会保持没有值,前提是它未用于用于偏序的类型中。[ 注意:在非推导上下文中使用的模板参数被视为已使用。— 尾注] [ 示例:
template <class T> T f(int); // #1 template <class T, class U> T f(U); // #2 void g() { f<int>(1); // calls #1 }
—结束示例]
用于部分排序的类型T...
根据[temp.deduct.partial]/3:
用于确定排序的类型取决于完成部分排序的上下文:
在函数调用的上下文中,使用的类型是函数调用具有参数的那些函数参数类型。
...
所以第一个未命名的模板参数包class...
不影响偏序的结果。由于两个函数模板没有其他区别,因此两者都没有比另一个更专业,从而导致模棱两可的调用。
这可能与 GCC 的bug 49505有关。
其次,即使第二个函数模板不存在,调用仍然应该是格式错误的。根据[temp.arg.explicit]/3:
...一个尾随模板参数包没有被推导出来,将被推导出为一个空的模板参数序列......
只有尾随模板参数包可以推导出为空包,而第一个未命名的模板参数包class...
不是尾随模板参数包。
推荐阅读
- javascript - Google Maps Api:始终在短模式下获取省份名称
- yahoo-fantasysports-api - 将 NFL Fantasy 得分数据导出到电子表格中
- sql - Powershell、invoke-sqlcmd、export-csv 如果有多个结果,则无法显示数据
- javascript - preventDefault() 不能正常工作
- azure-devops - Postman Oauth2.0 - 提供客户端凭据和请求 URI 时未收到回复地址错误
- google-data-studio - 当左侧数据集在 Google Data Studio 中重复时,如何仅从混合数据中获取一次值?
- sql - 我收到错误 ORA-00904: : invalid identifier (im a new in sql)
- go - 使用反射设置接口方法返回的接口值
- javascript - 为什么内容脚本(Chrome 扩展程序)没有收到我从 Chrome 页面操作弹出窗口发送的消息?
- rust - wasm-bindgen 元素 - 无法设置 id