允许在c ++ 1y中编写自动返回类型的规则是什么?
#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;
}
Run Code Online (Sandbox Code Playgroud)
函数体的圈复杂度是否存在限制?
函数体的圈复杂度是否存在限制?
我们
T是函数的变量或返回类型声明的类型.如果占位符是auto类型说明符,则使用模板参数推导的规则确定推导的类型.如果扣除是针对一个return语句而初始化器是一个 braced-init-list(8.5.4),那么程序就是格式错误.否则,获得P来自T替换的出现auto与新的发明类型模板参数U,或者,如果初始化是一个 支撑,初始化列表,用std::initializer_list<U>.U从函数调用(14.8.2.1)中减去使用模板参数推导规则的值 ,其中P是函数模板参数类型,初始化程序是相应的参数.如果扣除失败,则声明格式不正确.否则,推断出该变量或返回类型的类型是由代推导得到U成P.
所以,tl; dr:返回类型是return通过模板参数推导从语句中的表达式推导出来的.有一个虚构的模板,使用return语句中的表达式作为函数参数调用,推导出的模板参数U将替换占位符返回类型中的auto.现在,如果我们有多个return语句会怎么样?简单:我们推导出每个return语句,并检查它们是否兼容:
如果具有包含占位符类型的声明返回类型的函数具有多个
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;
}
Run Code Online (Sandbox Code Playgroud)
以下扣除完成:
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.
Run Code Online (Sandbox Code Playgroud)
当且仅当在两个调用中推导出相同的模板参数时,代码才是格式良好的.否则,扣除失败.如果使用auto说明符设置的返回类型不是简单auto但是例如auto const&,虚构模板的参数g具有相应的形式:
template<typename U>
void g(U const&);
Run Code Online (Sandbox Code Playgroud)
电话会是一样的.同样,如果推断出的Us不同,则代码是错误的.
如果您没有return语句,推导出的返回类型将是void,根据
如果具有使用占位符类型的声明返回类型的函数没有
return语句,则推断返回类型,就像return在函数体的右括号中没有操作数的语句一样.
如果你想要递归函数,它会变得更加棘手:
auto f( int a, int b )
{
return a? b + a : f(a-1, b); // This is ill-formed!
}
Run Code Online (Sandbox Code Playgroud)
以下引用解释了该问题:
如果需要具有未减少占位符类型的实体的类型来确定表达式的类型,则该程序是不正确的.
return但是,一旦在函数中看到了语句,从该语句推导出的返回类型就可以在函数的其余部分中使用,包括在其他return语句中.
所以我们写道:
auto f( int a, int b )
{
if( a )
return b + a;
return f(a-1, b);
}
Run Code Online (Sandbox Code Playgroud)
您可以使用任意复杂的函数,只要return语句在推导过程中都产生相同的类型,递归函数在一些非递归 - return语句之后具有递归调用.如有必要,可以使用相同的类型.
介绍
有一些简单的规则规定了何时可以从函数体推导出函数的返回类型,以及何时适用于返回类型。auto
这些规则都在标准 ( n3797 ) [1]中进行了说明,并且每条规则都在本文其余部分的其自己的部分中列出。
[1]第 7.1.6.4节中,自动说明符 [dcl.type.elab]。
有什么不能auto作为返回类型推断出来的吗?
[dcl.type.elab]p1如果推导是针对return语句且初始化器是花括号初始化列表 (8.5.4),则程序格式错误。
auto func () { return {1,2,3}; } // ill-formed
Run Code Online (Sandbox Code Playgroud)
如果一个函数有多个返回语句,将推导出哪种类型?
[dcl.type.elab]p9如果声明的返回类型包含占位符类型的函数具有多个返回语句,则将为每个返回语句推导返回类型。如果每次推导中推导的类型不相同,则该程序是格式错误的。
auto gunc_1 (bool val) { // (1), ill-formed
if (val) return 123;
else return 3.14f;
}
Run Code Online (Sandbox Code Playgroud)
auto gunc_2 (bool val) { // (2), legal
if (val) return static_cast<float> (123);
else return 3.14f;
}
Run Code Online (Sandbox Code Playgroud)
注意:(1)是格式错误的,因为所有返回语句都不是同一类型,而(2)是合法的,因为两个返回语句产生相同的类型。
如果函数没有return 语句会发生什么?
[dcl.type.elab]p10如果具有使用占位符类型的声明返回类型的函数没有 return 语句,则返回类型将像从函数体右大括号处没有操作数的 return 语句中推导一样。
auto hunc () { } // legal, return-type is `void`
Run Code Online (Sandbox Code Playgroud)
在推导返回类型之前我可以使用该函数吗?
[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
Run Code Online (Sandbox Code Playgroud)
auto recursive (int x) {
if (--x) return x + recursive (x); // (3), ill-formed
else return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意junc:我们不能获取内部的地址foo,因为这样做需要了解完整类型junc是什么,而只有在我们提供了推导返回类型的定义之前,我们才知道这一点。因此,(2)是合法的,而(1)则不合法。
注意:(3)recursive也是格式错误的,因为此时我们必须知道 的返回类型,但它是未知的。然而,以相反的顺序返回语句也是有效的。这样编译器就会知道在命中时recursive返回。intreturn x + recursive (x)
| 归档时间: |
|
| 查看次数: |
175 次 |
| 最近记录: |