令人困惑的非尾随参数包行为

时间:2016-08-08 10:56:05

标签: c++ templates language-lawyer

我遇到了一些有趣的可变参数模板函数行为。任何人都可以指出标准中定义这个的相关规则吗?

GCCICCMSVC成功编译了以下代码(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的此次调用中,为ABs提供了模板参数,然后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);
                                      ^

为了使事情变得更有趣,仅使用四个参数调用fooinvalid,第二个为valid

似乎在foo的第一个版本中,C 必须推断,而在第二个版本中,C 必须明确提供。

标准中的哪些规则定义了这种行为?

1 个答案:

答案 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) { }

以及以下致电(假设foofoo1foo2):

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必须明确提供所有模板参数。