【发布时间】:2016-10-05 08:21:18
【问题描述】:
考虑代码:
#include <tuple>
template<class... Args, class T>
T method(std::tuple<Args...>, Args..., T, ...) {
return T();
}
int main() {
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
1, 1.0f, 1.0, 1);
}
g++ 从 4.9 开始编译没有问题。另一方面,clang++ 提供了一个错误:
main.cpp:9:5: error: no matching function for call to 'method'
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
^~~~~~
main.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T'
T method(std::tuple<Args...>, Args..., T, ...) {
^
1 error generated.
哪个编译器是正确的?
【问题讨论】:
-
据我了解,它是这样工作的:顶层的
Args...不在参数列表的末尾,所以它出现在非推导上下文中,这使得Args...在模式匹配参数推导期间相当于一个 0 大小的参数子列表。因此,随后的T匹配出现在元组参数之后的1,并将推导出为int。稍后当编译器将参数int,float,double替换为Args...时,编译参数列表为tuple<...>,int,float,double,int。此列表需要匹配参数类型.. -
它在这种情况下是偶然的,因为最后一个
1的类型与第一个1的类型相同(实际上 GCC 似乎并不关心......它编译如果最后一个1是1.0.. 但有趣的是T保持int)。当三种类型的包扩展为Args...时,可能clang 放弃了将推断为int的T从其先前的推断参数位置移开,并报告它无法推断出T。跨度> -
如果你删除了
...,gcc 也不会编译它。 -
@W.F.实际上,Clang 也拒绝符合标准的测试代码,因此 Clang 在任何情况下都有一些未实现的功能(请参阅coliru.stacked-crooked.com/a/4350348b8080a730)。所以对于clang来说,原因是它还没有实现1388。对于 GCC,我不知道根据规范应该发生什么。直觉认为它应该失败,因为无法合理推断出
T。 -
啊,我们在open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1399 有一个像你这样的案例。本质上,1388 的“从未演绎”意味着它在其他可能可演绎的上下文中也没有被演绎。因此,在您的
tuple<Args...>中,它也不会为Args提供类型列表,因此最终结果是,您的代码格式不正确,因为Args将保持为空并且与提供的tuple<>不匹配论据。
标签: c++ g++ c++14 variadic-templates clang++