以下代码编译:
template<int...>
struct Indices {};
template<int J, int ...I>
void foo(Indices<I...>) {}
int main(int argc, char **argv)
{
foo<2>(Indices<3,4,5>()); //why does this work?
return 0;
}
在函数调用中,我认为J
参数变为2
而...I
参数变为3,4,5
?
但为什么这样呢?我只在2
指定了foo<2>
,这意味着我将J
指定为2
而...I
指定为空。为什么我仍然可以通过...I
参数指定Indices
?这里使用了什么模板机制?
更新:目前的答案并不能解释为什么我可以推断出一个不推断(明确指定)的参数,而推断其他参数。什么时候这确实有效?我希望我不依赖于未定义的行为。标准是否允许我正在做的事情?
答案 0 :(得分:6)
参数unpack ...I
由编译器从函数参数中推导 。它被称为template argument deduction。
以下是一些简单但有用的示例:
template<typename T>
void f(T const&) {}
f(10); //T is deduced as int
f(10.0); //T is deduced as double
f("10"); //T is deduced as char[3]
标准库中的许多函数都是函数模板,通常会推导出模板参数。这是一个例子:
std::vector<int> vi;
std::vector<std::string> vs;
//...
std::sort(vi.begin(), vi.end()); //template argument deduction
std::sort(vs.begin(), vs.end()); //template argument deduction
这里std::sort
是一个函数模板,但正如您所看到的,我们没有显式传递模板参数。这是因为模板参数是由编译器本身从函数参数推断出来的。
希望有所帮助。
答案 1 :(得分:2)
要添加到nawaz答案:必须提供无法推断的模板参数,并且提供的模板参数必须按照定义的顺序排列。这意味着如果模板参数可能需要提供,最好将其放在模板参数列表中的第一位。例如
template<typename A, typename B> A foo(B);
template<typename B, typename A> A bar(B);
auto x = foo<int>(0.0); // A=int, B=double;
auto y = foo<int,double>(0); // A=int, B=double, argument implicitly cast to double
auto z = bar<int>(0); // error: cannot deduce A
auto w = bar<int,double>(0); // A=double, B=int;
在这两种情况下都可以推导B
(来自函数参数类型),但A
不能。所以foo
更方便,因为只能提供一个模板参数。对于bar
,第一个模板参数是可推导的,但不是第二个。因此,必须提供两者。 (只是为了澄清转换auto
到double
或int
对于手头的问题没有任何区别。)
答案 2 :(得分:2)
如果可以在编译时推断出其他参数,则允许仅指定函数调用的参数的一部分(第一个)。例如:
template<typename Ret, typename Arg>
Ret cast(Arg x){
return x;
}
cast<double>(5);
实际上你甚至可以编译这段代码:
template<int...>
struct Indices {};
template<int J, int ...I>
void foo(Indices<I...>) {}
int main(int argc, char **argv)
{
foo<2,3>(Indices<3,4,5>()); //ok 2,3,4,5 starts with 2,3
return 0;
}
但不是这一个:
template<int...>
struct Indices {};
template<int J, int ...I>
void foo(Indices<I...>) {}
int main(int argc, char **argv)
{
foo<2,1>(Indices<3,4,5>()); //no way to make x,3,4,5 start with 2,1
return 0;
}
参见C ++ 11标准(N3242草案)第3部分第14.1.8节。
可以推导(14.8.2)或获得的尾随模板参数 来自默认模板 - 参数可以从列表中省略 显式模板参数。尾随模板参数包 (14.5.3)未以其他方式推导出的将被推断为空序列 模板参数。如果可以推导出所有模板参数, 它们都可以省略;在这种情况下,空模板参数 列表&lt;&gt;本身也可以省略。在演绎的情况下 完成和失败,或者在没有进行演绎的情况下,如果a 模板参数列表是指定的,它与任何默认值一起 模板参数,标识单个函数模板 特化,然后template-id是函数的左值 模板专业化。