请考虑以下代码:(Ideone)
struct S
{
int a() {return 0;}
decltype(a()) b() {return 1;}
};
它给了我以下错误:
错误:无法调用成员函数' int S :: a()'没有对象
另一方面,此代码编译良好:(Ideone)
struct S
{
int a() {return 0;}
auto b() -> decltype(a()) {return 1;}
};
为什么一个例子有效,但另一个例子无法编译?
两个示例中的编译器行为是否完全正确?
如果编译器是正确的,那么为什么标准要求这种奇怪的行为?
答案 0 :(得分:18)
由于a
是非静态成员函数,a()
被解释为(*this).a()
。引用部分来自[expr.prim.general] / 3,
如果声明声明了类
X
的成员函数或成员函数模板,则表达式this
是可选 cv-qualifer-seq 和结尾之间的“指向 cv-qualifier-seqX
的指针”的prvalue function-definition , member-declarator 或声明符。它不会出现在可选的 cv-qualifier-seq 之前 它不应出现在静态成员函数的声明中(尽管它的类型和值 category在静态成员函数中定义,因为它们在非静态成员函数中。)
trailing-return-type 位于可选的 cv-qualifier-seq 之后(在您的示例中省略,因为S::b
不是cv限定的)所以this
可以出现在那里,但之前不会出现。
答案 1 :(得分:10)
@Brian's answer的一些补充:
在第一个示例中,a()
未转换为(*this).a()
。该转换在[class.mfct.non-static]/3中指定,并且仅在可以使用this
的情况下发生#34;"。如果没有这种转换,代码就会因为违反[expr.prim.id]/2:
id-expression ,表示非静态数据成员或非静态数据成员 只能使用类的成员函数:
作为类成员访问([expr.ref])的一部分,其中对象表达式引用成员的类 63 或类 派生自该类,或
形成指向成员的指针([expr.unary.op])或
如果 id-expression 表示非静态数据成员,并且它出现在未评估的操作数中。
使用 id-expression a
,表示非静态成员函数,在允许的上下文之外。
转换为类成员访问权限的事实并不重要,因为它使以下代码有效:
struct A {
int a;
decltype(a) b();
};
如果上面的decltype(a)
转换为decltype((*this).a)
,那么代码就会格式不正确。
*this
特别豁免通常规则,即类成员访问中的对象必须具有完整类型([expr.prim.this]/2):
与其他上下文中的对象表达式不同,
*this
不需要为成员函数体外的类成员访问([expr.ref])的完整类型。