参加这个课程:
class Foo {
public:
using MyType = Foo;
MyType* m = nullptr; //ok
MyType* functor() { //ok
return nullptr;
}
MyType() = default; //error
~MyType() = default; //error
};
为什么可以为成员使用别名,但不能为构造函数或析构函数使用别名?
参加这个课程:
class Foo {
public:
using MyType = Foo;
MyType* m = nullptr; //ok
MyType* functor() { //ok
return nullptr;
}
MyType() = default; //error
~MyType() = default; //error
};
由于这被标记为language-lawyer
,让我们看看标准的规定。
从[class.ctor.gen]中,强调如下:
对于为什么名称别名不适用于声明构造函数,特别是(1.2)的相关性,这里需要进行阐述。它指出id-expression是injected-class-name[..]。后者在[class.pre]中定义:如果声明符是函数声明符([dcl.fct]),形式为ptr-declarator(parameter-declaration-clause)noexcept-specifieropt attribute-specifier-seqopt,则该声明符声明了一个构造函数,其中ptr-declarator仅由id-expression、可选的attribute-specifier-seq和可选的括号组成,且id-expression具有以下形式之一:
(1.1) 在友元声明([class.friend])中,id-expression是一个限定的id,它命名了一个构造函数([class.qual]);
(1.2) 否则,在属于类或类模板的成员说明的成员声明中,id-expression是最近封闭实体的注入类名([class.pre]);
(1.3) 否则,id-expression是一个限定-id,其未限定-id是其查找上下文的注入类名。
这非常明确地说明,注入类名恰好是用于首次声明类的名称。在措辞中没有别名的容忍余地。
- 类是一种类型。其名称在其范围内成为类名([class.name])。
[..]- 类名也绑定在类(模板)本身的作用域中;这被称为注入类名。 为了进行访问检查,注入类名被视为公共成员名称。[..]
template <typename T> class C { C foo(); };
C
的类,C
是一个模板,因此您通常希望使用C<T> foo();
。但是如[class.pre]中所述,在类定义的作用域中引入了一个class-name,该名称指向实际类型。因此,即使没有任何类C
,class-name C
也可以用作C<T>
的简写,在构造函数和析构函数的情况下,这是唯一的引用方式,因为它们的声明不允许使用任何类型标识符,但class-name只能使用。m
是指向别名类型实例的指针。没问题。
functor()
返回指向别名类型实例的指针。没问题。
但是构造函数/析构函数本身不是类型,因此您不能为它们使用类型别名。它们必须以所属类型命名。这只是语法工作的方式。