C++ 为什么这个函数模板调用有效?
编译以下代码:C++ 为什么这个函数模板调用有效?,c++,templates,c++11,C++,Templates,C++11,编译以下代码: 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; } 模板 结构索引{}; 模板 void foo
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;
}
模板
结构索引{};
模板
void foo(索引){}
int main(int argc,字符**argv)
{
foo(index());//为什么这样做?
返回0;
}
在函数调用中,J
参数变为2
,而…I
参数变为3,4,5
但这为什么有效呢?我只在foo
处指定了2
,意思是我将J
指定为2
,而…I
指定为无。为什么我仍然可以通过索引
参数指定…I
?这里使用的模板机制是什么
更新:当前的答案没有解释为什么我可以有一个参数没有推导(明确指定),但其他参数可以推导。这到底什么时候起作用?我希望我没有依赖未定义的行为。标准是否允许我执行上述操作?编译器根据函数参数推断参数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]
模板
空f(T常数&){}
f(10)//T被推导为int
f(10.0)//T被推导出为双
f(“10”)//T被推断为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::vector vi;
std::向量vs;
//...
排序(vi.begin(),vi.end())//模板实参推演
排序(vs.begin(),vs.end())//模板实参推演
这里的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;
模板A foo(B);
模板A条(B);
自动x=foo(0.0);//A=int,B=double;
自动y=foo(0);//A=int,B=double,参数隐式转换为double
自动z=bar(0);//错误:无法推断错误
自动w=条(0);//A=double,B=int;
在这两种情况下,
B
都可以推断(从函数参数类型推断),但A
不能。因此foo
更方便,因为只需提供一个模板参数。使用条
,可以推断第一个模板参数,但不能推断第二个模板参数。因此,两者都必须提供。(只是澄清一下,将auto
更改为double
或int
与当前的问题没有任何区别。)如果可以在编译时推断出其他参数,则只允许为函数调用指定部分参数(第一个参数)。例如:
template<typename Ret, typename Arg>
Ret cast(Arg x){
return x;
}
cast<double>(5);
模板
复铸(Arg x){
返回x;
}
铸造(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;
}
模板
结构索引{};
模板
void foo(索引){}
int main(int argc,字符**argv)
{
foo(index());//确定2,3,4,5以2,3开头
返回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;
}
模板
结构索引{};
模板
void foo(索引){}
int main(int argc,字符**argv)
{
foo(index());//无法使x,3,4,5以2,1开头
返回0;
}
参见C++11标准(N3242草案)的§14.1.8第3部分
可以推导(14.8.2)或获得的尾部模板参数
默认模板参数可以从
显式模板参数。尾部模板参数包
(14.5.3)未经其他推导的将被推导为一个空序列
模板参数。如果可以推导出所有模板参数,
它们都可以省略;在本例中,空模板参数
列表本身也可以省略。在需要演绎的情况下
完成和失败,或在未进行扣除的情况下,如果
模板参数列表是指定的,它与任何默认值一起使用
模板参数,标识单个函数模板
专门化,则模板id是函数的左值
模板专门化
我不知道我可以推导出一些参数,而不能推导出其他参数。你能详细说明一下吗?@roger.james:好吧,现在你可以了。使用函数模板,您可以显式指定从第一个开始并在任何时候停止的参数。编译器将尝试推断其余部分。当您说
foo(index)
时,您已经在模板函数中输入了一种类型的index
。由于输入类型在编译时已知,并且该类型对应于第二个模板参数,因此编译器可以将
与
匹配,并生成正确的函数。