我遇到了一些有趣的可变参数模板函数行为。任何人都可以指出标准中定义这个的相关规则吗?
GCC,ICC和MSVC成功编译了以下代码(Clang没有,但我知道这是由于编译器错误)。
template<class A, class... Bs, class C>
void foo(A, Bs..., C) { }
int main()
{
foo<int, int, int, int>(1, 2, 3, 4, 5);
}
在对foo
的此次调用中,为A
和Bs
提供了模板参数,然后C
被推断为int
。
但是,如果我们只是翻转最后两个模板参数:
template<class A, class C, class... Bs>
void foo(A, Bs..., C) { }
然后all three compilers抛出错误。以下是海湾合作委员会的成员:
main.cpp: In function 'int main()':
main.cpp:8:42: error: no matching function for call to 'foo(int, int, int, int, int)'
foo<int, int, int, int>(1, 2, 3, 4, 5);
^
main.cpp:4:6: note: candidate: template<class A, class C, class ... Bs> void foo(A, Bs ..., C)
void foo(A, Bs..., C) { }
^~~
main.cpp:4:6: note: template argument deduction/substitution failed:
main.cpp:8:42: note: candidate expects 4 arguments, 5 provided
foo<int, int, int, int>(1, 2, 3, 4, 5);
^
为了使事情变得更有趣,仅使用四个参数调用foo
为invalid,第二个为valid。
似乎在foo
的第一个版本中,C
必须推断,而在第二个版本中,C
必须明确提供。
标准中的哪些规则定义了这种行为?
答案 0 :(得分:2)
通常情况下,我在发布问题几个小时后就找到了答案。
考虑foo
的两个版本:
template<class A, class... Bs, class C>
void foo1(A, Bs..., C) { }
template<class A, class C, class... Bs>
void foo2(A, Bs..., C) { }
以及以下致电(假设foo
为foo1
或foo2
):
foo<int,int,int,int>(1,2,3,4,5);
对于foo1
,模板参数选择如下:
A = int (explicitly provided)
Bs = {int,int,int} (explicitly provided)
C = int (deduced)
但在foo2
的情况下,它们看起来像这样:
A = int (explicitly provided)
C = int (explicitly provided)
Bs = {int,int} (explicitly provided)
Bs
位于非推导的上下文([temp.deduct.type]/5.7
)中,因此任何其他函数参数都不能用于扩展包。因此,foo2
必须明确提供所有模板参数。