Twi*_*ard 3 c++ alias language-lawyer
参加这堂课:
class Foo {
public:
using MyType = Foo;
MyType* m = nullptr; //ok
MyType* functor() { //ok
return nullptr;
}
MyType() = default; //error
~MyType() = default; //error
};
Run Code Online (Sandbox Code Playgroud)
为什么可以对成员使用别名,但不能对构造函数或析构函数使用别名?
由于它被标记为language-lawyer,让我们看看标准怎么说。
从[class.ctor.gen]中,添加了重点:
如果声明符是 ptr-declarator (parameter-declaration-clause) noexcept-specifieropt attribute-specifier-seqopt 形式的函数声明符 ([dcl.fct]),则声明符声明构造函数,其中 ptr-declarator 仅包含 id-表达式、可选的属性说明符序列和可选的括号,并且 id-表达式具有以下形式之一:
(1.1) 在友元声明 ([class.friend]) 中,id-表达式是命名构造函数 ([class.qual]) 的限定 ID;
(1.2)否则,在属于类或类模板的成员规范的成员声明中,id 表达式是直接封闭实体的注入类名 ([class.pre]);
(1.3) 否则,id-表达式是一个限定 ID,其非限定 ID 是其查找上下文的注入类名称。
对于为什么名称别名对于声明构造函数无效的主题,特别是(1.2)是相关的。它声明id-expression 是注入的类名[..]。后者在[class.pre]中定义:
- 类是一种类型。它的名称在其范围内成为类名称([class.name])。
[..]- 类名也绑定在类(模板)本身的范围内;这称为注入类名。出于访问检查的目的,注入的类名称被视为公共成员名称。[..]
这非常清楚地表明,注入的类名正是最初用于声明类的名称。措辞中不允许使用别名。
这遵循与您在类模板中看到的相同机制:
template <typename T> class C { C foo(); };
Run Code Online (Sandbox Code Playgroud)
现在,没有名为 的类C,C是模板,因此您通常会期望必须说C<T> foo();。但正如 [class.pre] 中所述,在类定义的范围内引入了一个类名,它引用实际类型。因此,即使任何地方都没有类C,类名也 C可以用作构造函数和析构函数的简写C<T>,这是引用它的唯一方法,因为它们的声明不允许您使用任何类型 - id,但只有 类名。