何时可以应用自动返回类型
When can automatic return type apply?
在 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;
}
函数体的圈复杂度是否有限制?
函数的圈复杂度是否有限制 身体?
标准规定的内容 (N3797, §7.1.6.4(:
设
T
变量的声明类型或返回类型 功能。 如果占位符是auto
类型说明符,则推导 类型是使用模板参数推断规则确定的。如果 扣除额用于return
语句,初始值设定项为 大括号初始化列表 (8.5.4(,程序格式不正确。 否则T
通过将auto
的出现次数替换为新的P
发明的类型模板参数U
或者,如果初始值设定项是 带大括号的初始化列表,带有std::initializer_list<U>
.推导一个值U
使用从函数调用中扣除模板参数的规则 (14.8.2.1(,其中P
是函数模板参数类型,而 初始值设定项是相应的参数。如果扣除失败, 声明格式不正确。否则,推导的类型为 变量或返回类型是通过将推导的U
代入获得的P
.
因此,tl;dr:返回类型是通过模板参数推导从return
语句中的表达式推导出来的。有一个虚构的模板,它被调用,return
语句中的表达式作为函数参数,推导的模板参数U
将成为占位符返回类型中 auto 的替代品。现在,如果我们有多个返回语句会发生什么?简单:我们推断出每个return
语句,并检查它们是否兼容:
如果函数具有包含占位符的声明返回类型 类型有多个
return
语句,返回类型推导为 每个return
语句。如果推导的类型在每个中都不相同 演绎,n程序格式不正确。
因此,对于此代码:
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
而是例如 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
-语句之后具有递归调用。如有必要,请强制转换以获得相同的类型。
简介
有一些简单的规则可以说明何时可以从函数体中推断出函数的返回类型,以及何时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
如果一个函数有多个返回语句,将推导出哪种类型?
[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( 格式不正确,因为所有返回语句都不是同一类型,而 (2( 是合法的,因为两个返回语句产生相同的类型。
如果函数没有返回语句会发生什么情况?
[dcl.type.elab]p10
如果声明返回类型的函数使用占位符类型没有 return 语句,则返回类型就像从函数体右大括号处没有操作数的 return 语句中推导的那样。
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;
}
注意:我们不能在foo
中获取junc
的地址,因为这样做需要了解完整的junc
类型是什么,直到我们提供了推断返回类型的定义才能知道。(2(因此是合法的,而(1(不是。
注意:(3( 也是格式错误的,因为此时我们必须知道recursive
的返回类型,但不知道。但是,以相反的顺序使用返回语句将是有效的。这样编译器就会知道recursive
在遇到return x + recursive (x)
时返回int
。
- 如何获取std::result_of函数的返回类型
- 奇怪的结构&GCC&clang(void*返回类型)
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 函数作为模板参数,是否对返回类型强制约束
- C++中函数的向量返回类型引发错误
- 检查函数返回类型是否与STL容器类型值相同
- 为什么返回类型中需要typename?C++
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 为什么 c++(g++) 不允许模板返回类型和函数名称之间有空格?
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 推导 std::vector::back() 的返回类型
- 返回类型的声明类型时,应用于三元(?:)表达式
- C++协变返回类型应用程序
- 将using语句应用于函数的返回类型,而不应用于整个命名空间
- 在C/ c++或任何其他类似语言中,对变量或数据类型应用&符号时返回的地址类型
- 何时可以应用自动返回类型