Vit*_*meo 6 c++ return-type language-lawyer c++11 trailing-return-type
尾随返回类型允许在以下两种情况下简化代码:
从类的成员函数之一返回在类内部定义的类型:
struct X
{
using foo = int;
foo f();
};
// pre-C++11
X::foo X::f() { /* ... */ }
// trailing, doesn't require `X::` before `foo`
auto X::f() -> foo { /* ... */ }
Run Code Online (Sandbox Code Playgroud)返回复杂的类型,例如函数指针类型:
// pre-C++11
int(*g(float))(int) { /* ... */ }
// trailing, easier to read
auto f(float) -> int(*)(int) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)我正在尝试查找Standard的相关部分,以解释上述两种简化的工作方式。我已经看过[basic.lookup]
并略过了trailing-return
,但是找不到任何简单的方法可以解释上述转换的工作原理。
我错过了吗?
标准的哪些部分解释了以上的尾随回返型简化形式?
对于 #1,请参阅 C++17 [basic.lookup.qual]/3:
\n\n\n\n\n在declarator-id是Qualified-id的声明中,在声明的Qualified-id之前使用的名称会在定义的命名空间范围中查找;限定 ID后面的名称在成员的类或命名空间的范围内查找
\n
普通的前导返回类型位于declarator-id之前,即X::f
在命名空间范围内查找它。它后面有一个尾随返回类型,因此可以在类作用域中查找它。
对于 #2,请观察Trailing-return-type的语法对于 #2,观察[dcl.decl]/4 中的
\n\n\n\n\n\n
->
类型 ID
根据 [dcl.fct]/2,该类型是函数的返回类型。
\n\n如果要使用前导返回类型,则必须通过 [dcl.fct]/1 递归确定函数的返回类型:
\n\n\n\n\n在声明中,
\n\nT D
其中D
以下形式\n\n\n\n
D1
(
参数声明子句)
cv-qualifier-seq (opt) ref-qualifier (opt) noexcept-specifier (opt) attribute-specifier-seq (opt)声明中包含的declarator-id的类型
\nT D1
为 \xe2\x80\x9c派生声明符类型列表 \xe2\x80\x9d,其中declarator-idT
的类型为 \xe2\x80\x9c派生-声明符类型列表noexcept (opt) 参数声明子句的函数\n cv-qualifier-seq (opt) ref-qualifier (opt) 返回D
(
)
T
\xe2\x80\x9d,其中 ...
这里,T
代表一个decl-specifier-seq。如果你有一个typedef-name表示int(*)(int)
,比如说,FPII
,那么你可以使用它:
FPII g(float);\n
Run Code Online (Sandbox Code Playgroud)\n\n但如果你想以困难的方式做到这一点,我们必须找到T
和D1
,这样当导出声明符类型列表(即类型转换的序列将根据 的语法形式D1
施加)应用于“函数”时,返回“,结果是”返回指针的函数(返回的函数T
D1
int
T
float
int
int
”。
float
如果派生声明符类型列表是“返回指针的函数”并且T
是,则满足这一点int
。因此,声明符D1
必须具有语法形式*
declarator-id (float)
,以便产生所述派生声明符类型列表。我们必须添加一对额外的括号,以便在整个声明中获得正确的绑定。
这里没有发生从尾随返回类型到前导返回类型的“转换”。相反,尾随返回类型仅允许您直接指定返回类型,而前导返回类型则由递归解包声明符的算法进行解释。虽然这在“声明遵循使用”的原则下是有意义的,但对于人类(包括经验丰富的 C++ 程序员)来说,直观地掌握它往往有点困难。尤其是当我们必须反向执行时(写下声明,而不是解释现有声明)。
\n 归档时间: |
|
查看次数: |
153 次 |
最近记录: |