有哪些规则,允许在c ++ 1y中使用writing自动返回类型?
#include <iostream>
using namespace std;
template<typename T1, typename T2>
auto f(T1 const& a, T2 const &b)
{
if (a > b) return a-b;
else return a+b;
}
int main()
{
cout << f(1, 2.) << endl;
return 0;
}
函数体的圈复杂度是否存在限制?
答案 0 :(得分:7)
函数的圈复杂度是否存在限制 体?
让
T
成为变量的声明类型或返回类型 功能。如果占位符是auto
类型说明符,则推导出 type是使用模板参数推导的规则确定的。如果 扣除是针对return
语句而初始值设定项是 braced-init-list (8.5.4),该程序格式错误。除此以外, 通过将P
的出现替换为新值,从T
获取auto
发明了类型模板参数U
,或者,如果初始化器是a braced-init-list ,std::initializer_list<U>
。推断一个值U
使用函数调用中的模板参数推导规则 (14.8.2.1),其中P
是函数模板参数类型和 初始化程序是相应的参数。如果扣除失败,那么 声明是不正确的。否则,推断出的类型 变量或返回类型是通过将推导出的U
代入P
。
所以,tl; dr:返回类型是通过模板参数推导从return
语句中的表达式推导出来的。有一个假想的模板,使用return
语句中的表达式作为函数参数调用,推导出的模板参数U
将替换占位符返回类型中的auto。
现在,如果我们有多个return语句会发生什么?简单:我们推导出每个return
语句,并检查它们是否兼容:
如果具有声明的返回类型的函数包含占位符 type有多个
return
语句,推导出返回类型 每个return
声明。如果推断出的类型在每个中都不相同 扣除,该计划是不正确的。
所以,对于这段代码:
template<typename T1, typename T2>
auto f(T1 const& a, T2 const &b)
{
if (a > b) return a-b;
else return a+b;
}
以下扣除完成:
template<typename U>
void g(U);
g( a-b );
g( a+b );
// here, a and b have the exact same types as in a specialization of the template above.
当且仅当在两个调用中推导出相同的模板参数时,代码才是格式良好的。否则,扣除失败。如果您使用自动说明符设置的返回类型不是简单的auto
,而是例如auto const&
,则虚构模板g
的参数具有相应的格式:
template<typename U>
void g(U const&);
电话会是一样的。同样,如果推断的U
不同,则代码格式不正确。
如果您有无退货声明,根据
,推断的退货类型将为void
如果具有声明的返回类型的函数使用占位符类型 没有
return
语句,返回类型就像是从中推断出来的 一个return
语句,在结束括号中没有操作数 功能体。
如果您想要递归函数:
,这会变得更加棘手auto f( int a, int b )
{
return a? b + a : f(a-1, b); // This is ill-formed!
}
以下引用解释了这个问题:
如果需要具有未减少占位符类型的实体的类型 为了确定表达式的类型,程序是不正确的。 但是,一旦在函数中看到
return
语句,就会出现 从该语句推导出的返回类型可以在其余部分中使用 函数,包括在其他return
语句中。
所以我们写一下:
auto f( int a, int b )
{
if( a )
return b + a;
return f(a-1, b);
}
你可以使用任意复杂的函数,只要return
语句在推导过程中都产生相同的类型,递归函数在一些非递归return
语句之后具有递归调用。如有必要,可以使用相同的类型进行投射。
答案 1 :(得分:3)
<强>简介强>
有一些简单的规则说明何时可以从函数体推导出函数的 return-type ,并在auto
时推断出适用于 return-type 。
这些规则都在标准(n3797) [1] 中说明,并且每篇规则都列在本文其余部分的自己的部分中。
7.1.6.4 自动说明符 [dcl.type.elab]
有什么不能使用auto
作为返回类型推断出来吗?
[dcl.type.elab]p1
如果扣除的是return
语句且初始化程序是braced-init-list(8.5.4),则程序格式错误。
auto func () { return {1,2,3}; } // ill-formed
如果某个函数有多个 return-statement ,将推断出哪种类型?
[dcl.type.elab]p9
如果具有包含占位符类型的声明返回类型的函数具有多个return语句,则会为每个return语句推导出返回类型。如果推断的类型在每次扣除中不相同,则该程序格式不正确。
auto gunc_1 (bool val) { // (1), ill-formed
if (val) return 123;
else return 3.14f;
}
auto gunc_2 (bool val) { // (2), legal
if (val) return static_cast<float> (123);
else return 3.14f;
}
注意:(1)格式不正确,因为所有 return-statements 的类型不同,而< em>(2)是合法的,因为两个 return-statements 产生相同的类型。
如果该功能没有 return-statement 会怎样?
[dcl.type.elab]p10
如果具有使用占位符类型的声明返回类型的函数没有返回语句,则推断返回类型,就好像从返回语句中结束时没有操作数一样功能体的支撑。
auto hunc () { } // legal, return-type is `void`
我可以在推断出返回类型之前使用该函数吗?
[dcl.type.elab]p11
如果需要具有未减少占位符类型的实体类型来确定表达式的类型,则程序格式错误。但是,一旦在函数中看到了return语句,从该语句推导出的返回类型就可以在函数的其余部分中使用,包括在其他return语句中。
auto junc (); // declaration
void foo () { &junc; } // (1), ill-formed
auto junc () { // definition
return 123;
}
void bar () { &junc; } // (2), legal
auto recursive (int x) {
if (--x) return x + recursive (x); // (3), ill-formed
else return 0;
}
注意:我们无法在junc
内获取foo
的地址,因为这样做需要了解junc
的完整类型是什么,在我们提供了推断出返回类型的定义之前,我们不知道的事情。 (2)是合法的,而(1)不是
注意:(3)也是格式错误的,因为此时我们必须知道recursive
的返回类型,但它不知道。但是,以相反的顺序使返回语句有效。这样,编译器会知道recursive
在int
命中时返回return x + recursive (x)
。