在一个类内部,为什么'auto b() -> decltype(a()) {}'有效,而'decltype(a()) b() {}'不起作用?
Inside of a class, why `auto b() -> decltype(a()) {}` works, but `decltype(a()) b() {}` does not?
请考虑以下代码:(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;}
};
为什么一个示例有效,而另一个示例无法编译?
这两个示例中的编译器行为是否完全正确?
如果编译器是正确的,那么为什么标准要求这种奇怪的行为呢?
由于a
是一个非静态成员函数,因此a()
被解释为(*this).a()
。部分引自[expr.prim.general]/3,
如果声明声明了类
X
的成员函数或成员函数模板,则表达式this
是可选的 CV-qualifer-seq 之间的类型为 "指向 cv-qualifier-seqX
的指针"的 prvalue 函数定义、成员声明符或声明符。它不应出现在可选的 cv 限定符-seq 之前 并且它不应出现在静态成员函数的声明中(尽管它的类型和值 类别在静态成员函数中定义,因为它们在非静态成员函数中定义(。
尾随返回类型位于可选的 cv 限定符 seq 之后(在您的示例中省略,因为S::b
不符合 cv 条件(,因此this
可以出现在那里,但它不能出现在之前。
@Brian的答案有一些补充:
-
在第一个示例中,
a()
不会转换为(*this).a()
。该转换在 [class.mfct.non-static]/3 中指定,并且仅在"可以使用this
的上下文中"发生。如果没有此转换,则代码的格式不正确,无法违反 [expr.prim.id]/2:表示非静态
数据成员或非静态数据的 id 表达式 类的成员函数只能用于:
作为类成员访问 ([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(:与其他上下文中的对象表达式不同,对于成员函数体外部的类成员访问 ([expr.ref](,
*this
不需要是完整类型。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 在c++中用vector填充一个简单的动态数组
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 预处理器:插入结构名称中的前一个行号
- 我在c++代码中生成了一个运行时#3异常
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 使用具有默认参数的函数模板进行 decltype 会使结果混乱(一个有趣的问题或 gcc 的错误)
- 如果我将 decltype 应用于产生右值的表达式,我是否总是得到一个指针?C++
- 如何用decltype实现一个不太通用的std::is_constructible
- 在一个类内部,为什么'auto b() -> decltype(a()) {}'有效,而'decltype(a()) b() {}'不起作用?
- 我们可以在另一个成员函数的参数列表中使用一个成员函数的 decltype 吗?
- do decltype 需要一个涉及完整类型的表达式
- C#是否有一个等价于C++11中的decltype
- decltype的另一个问题