为什么这个函数模板调用有效
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
指定为无。为什么我仍然可以通过Indices
参数指定...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]
标准库中的许多函数都是函数模板,通常会推导出模板参数。这里有一个例子:
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
是一个函数模板,但正如您所看到的,我们没有显式传递模板参数。这是因为模板参数是由编译器自己从函数参数中推导出来的。
希望能有所帮助。
如果在编译时可以推导出其他参数,则只允许指定函数调用的部分参数(第一个)。示例:
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;
}
请参阅§14.1.8 C++11标准第3部分(N3242草案)。
可以推导(14.8.2)或获得的尾随模板参数from默认模板参数可以从显式模板参数。尾部模板参数包(14.5.3)将被推导为模板参数。如果可以推导出所有的模板自变量,它们可以全部省略;在这种情况下,空模板参数列表<>也可以省略其本身。在演绎是完成和失败,或者在没有进行推理的情况下,如果模板参数列表是指定的,它以及任何默认值模板参数,标识单个函数模板specialization,则模板id是函数的左值模板专业化。
要添加到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
与手头的问题没有区别。)
- 函数参数的名称与调用函数时使用的变量相同是否有效?
- 为什么使用不匹配的参数调用重载函数仍然有效
- 通过指针调用模板类成员函数 [为什么这是有效的 c++]?
- 为什么构造函数的虚拟函数调用有时有效,但其他调用却无效
- 除了字符串或宏调用之外,是否存在任何情况,其中"(<"是有效的字符流?
- 让构造函数在其初始化列表中调用同一类的另一个构造函数是否有效
- boost::asio 使用 post() 时没有调用处理程序,当直接调用函数时有效(io_context有工作)
- “A a = A()”有效吗?下面调用了哪些运算符/方法
- 从第二个线程调用Qt信号有效 - >对连接的插槽没有影响
- 重构后,异步调用方法不再有效
- qt5 QGraphicsScene setBackgroundBrush()在频繁调用时并不总是有效
- 在C++中嵌入Python:在Python脚本中导入模块在一个函数调用过程中有效,但在另一个调用过程中无效
- 系统( "command" ) 产生错误;但它在直接从 Bash 提示符调用时有效
- 当从一个应用程序调用时,在DLL方法中创建COM接口指针是有效的,但当从另一个应用软件调用时则无效
- 如何在constexpr函数中有效地调用_BitScanReverse或__builtin_clz
- 在UDP套接字上多次调用Connect()以发送到不同的目标地址 - 有效
- 将基类的引用传递给 boost::thread 并在派生类中调用虚函数是否有效
- C++如何判断static.lib是否有效,是否可从外部代码调用
- 调用不带参数的构造函数有效,使用参数则无效。为什么?
- 为什么这个函数模板调用有效