对于 #1,请参阅 C++17 [basic.lookup.qual]/3:
在declarator-id是qualified-id的声明中,在声明的qualified -id之前使用的名称在定义的命名空间范围内查找;在成员的类或命名空间的范围内查找限定 ID之后的名称。
一个普通的前导返回类型在declarator-id之前,即X::f
在命名空间范围内查找它。尾随返回类型跟随它,因此在类范围内查找它。
对于 #2,请注意[dcl.decl]/4 中的trailing-return-type的语法是:
->
类型标识
并且根据 [dcl.fct]/2,该类型是函数的返回类型。
如果要使用前导返回类型,则函数返回类型的确定必须由 [dcl.fct]/1 递归确定:
在有表格的声明T D
中D
D1
(
参数声明子句 )
cv-qualifier-seq (opt) ref-qualifier (opt) noexcept-specifier (opt) attribute-specifier-seq (opt)
并且声明中包含的declarator-id的类型T D1
是“<em>derived-declarator-type-list T
”,其中declarator-id的类型D
是“<em>derived-declarator-type-list noexcept (opt)(
参数声明子句的函数)
cv-qualifier-seq (opt) ref-qualifier (opt) 返回T
”,其中 ...
这里,T
表示一个decl-specifier-seq。如果您有一个表示的typedef-nameint(*)(int)
,例如FPII
,那么您可以使用它:
FPII g(float);
但是,如果您想以艰难的方式做到这一点,我们必须找到T
andD1
这样,当派生声明符类型列表,即根据 的句法形式D1
施加的类型转换序列,应用于“函数返回" ,结果是"返回指针的函数(返回函数)"。T
D1
int
T
float
int
int
如果派生声明符类型列表是“float
返回指针的函数”,并且T
是int
. 因此,声明符D1
必须具有语法形式*
declarator-id (float)
才能产生所述派生声明符类型列表。为了使整个声明中的绑定正确,我们必须添加一对额外的括号。
这里没有从尾随返回类型到前导返回类型的“转换”。相反,尾随返回类型只允许您直接指定返回类型,而前导返回类型由这种递归解包声明符的算法解释。虽然这在“声明遵循使用”的原则下是有道理的,但对于人类(包括非常有经验的 C++ 程序员)来说,直观地掌握它往往有点困难。尤其是当我们必须反过来做时(写下声明,而不是解释现有的声明)。