[英]Why does this function template call work?
以下代码编译:
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
?
但为什么这有效呢? 我只在foo<2>
指定了2
,这意味着我将J
指定为2
并且...I
没有任何指示。 为什么我仍然可以指定...I
通过Indices
参数? 这里使用了什么模板机制?
更新:当前的答案并没有解释为什么我可以有一个参数没有推断(明确指定)但其他参数推断。 什么时候这确实有效? 我希望我不依赖于未定义的行为。 标准是否允许我正在做的事情?
参数unpack ...I
是由编译器从函数参数中推导出来的。 它被称为模板参数推导 。
以下是一些简单但有用的示例:
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
是一个函数模板,但正如您所看到的,我们没有显式传递模板参数。 这是因为模板参数是由编译器本身从函数参数推导出来的。
希望有所帮助。
要添加到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
,第一个模板参数是可推导的,但不是第二个。 因此,必须提供两者。 (只是为了澄清changning auto
to double
或int
与手头的问题无关。)
如果可以在编译时推断出其他参数,则允许仅为函数调用指定部分参数(第一个)。 例:
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草案)的第14.1.8部分第3节。
可以推导出(14.8.2)或从默认模板参数获得的尾随模板参数可以从显式模板参数列表中省略 。 未以其他方式推导出的尾随模板参数包(14.5.3)将被推导为空的模板参数序列。 如果可以推导出所有模板参数,则可以省略它们; 在这种情况下,也可以省略空模板参数列表<>本身。 在完成演绎和失败的上下文中,或者在没有进行演绎的上下文中,如果指定了模板参数列表,并且它与任何默认模板参数一起识别单个函数模板特化,那么template-id是左值用于功能模板专业化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.