以下代码适用于gcc-4.8.2
#include <iostream>
using namespace std;
template<typename... Args>
void func(Args... args, int optional = 0)
{
cout << optional << endl;
}
int main()
{
func(1);
func(2.1f); // converts 2.1 to int as 'optional' parameter
func<float>(3.3f); // Fine, prints '0'
func(); // gcc OK, fails to compile with clang-3.5
}
它输出:
$ ./a.out
1
2
0
0
但是如果用clang-3.5编译失败,
test_variadic.cpp:15:2: error: no matching function for call to 'func'
func();
^~~~
test_variadic.cpp:5:6: note: candidate function template not viable: requires at least argument 'args', but no arguments were provided
void func(Args... args, int optional = 0)
^
Clang至少警告从float到int的隐式转换。好的,我们可以通过调用将func<float>
放入模板包中的func()
来纠正它。所以,如果我评论func()
,它编译得很好。
我无法在标准中找到任何明确说明变量模板包必须是参数声明子句中的最后一件事,只是它变成了非推导的上下文。
我的困惑来自于当func(1)
完全可以接受时,为什么clang不喜欢func(int optional = 4) { cout << optional << endl; }
。我可以手动定义int
并且一切都很好(但是在传递func()
时我没有使用模板化函数我在clang和gcc中正确获得了专门的func()
。什么是clang强制执行限制使用{{1}}?
答案 0 :(得分:3)
这实际上是由略微错位的[temp.arg.explicit]/3:
覆盖的尾随模板参数包(14.5.3)没有 否则推断将被推导出一个空的模板参数序列。
模板参数包是尾随的,因此在除func<float>(3.3f)
之外的所有调用中推断为空包,也就是说,它们都是有效的(并且Clang将它们编译得很好as of 3.5)。
但是,一旦我们将模板的声明调整为
,编译器就不再符合要求了template <typename... Args, typename=void>
void func(Args... args, int optional = 0)
现在,上述引用不适用(因为Args
没有结尾)而[temp.deduct.call]/1适用:
当函数参数包出现在非推导的上下文中时 (14.8.2.5),从不推断出该参数包的类型。
(即,这应该会导致演绎失败。)