Tar*_*ama 10 c++ templates language-lawyer
我遇到了一些有趣的可变参数模板函数行为.任何人都能指出标准中定义此规则的相关规则吗?
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);
}
Run Code Online (Sandbox Code Playgroud)
在此呼吁foo
,提供了模板参数为A
和Bs
,然后C
推断为int
.
但是,如果我们只是翻转最后两个模板参数:
template<class A, class C, class... Bs>
void foo(A, Bs..., C) { }
Run Code Online (Sandbox Code Playgroud)
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);
^
Run Code Online (Sandbox Code Playgroud)
为了让事情更有趣,只用四个参数调用是无效的第一foo
,并有效第二.
看来,在第一个版本foo
,C
必须被推断,而在第二,C
必须明确提供.
标准中的哪些规则定义了这种行为?
通常情况下,我在发布问题几个小时后就得到了答案。
考虑以下两个版本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) { }
Run Code Online (Sandbox Code Playgroud)
和以下调用(假设foo
是foo1
or foo2
):
foo<int,int,int,int>(1,2,3,4,5);
Run Code Online (Sandbox Code Playgroud)
在 的情况下foo1
,模板参数的选择如下:
A = int (explicitly provided)
Bs = {int,int,int} (explicitly provided)
C = int (deduced)
Run Code Online (Sandbox Code Playgroud)
foo2
但在它们看起来像这样的情况下:
A = int (explicitly provided)
C = int (explicitly provided)
Bs = {int,int} (explicitly provided)
Run Code Online (Sandbox Code Playgroud)
Bs
位于非推导上下文 ( [temp.deduct.type]/5.7
) 中,因此任何其他函数参数都不能用于扩展包。因此,foo2
必须显式提供所有模板参数。