我最近了解到在C++中构造函数没有名称以及关于它们的其他一些事情。我还知道函数在 C++ 中有一种称为“函数类型”的类型。例如,
void func(int)
{
}
在上面的代码片段中,
func
具有
函数类型
void (int)
。现在,我想知道,既然构造函数是特殊的成员函数,那么它们是否也有像上面所示的类型。例如,假设我们有:
struct Name
{
Name(int)
{
}
};
上面所示的构造函数是否也像普通函数或普通成员函数一样具有函数类型
?如果是,那么我们如何找到该类型。就像我们可以在普通函数上使用 decltype
一样,是否可以在构造函数上使用
decltype
来查找其类型。decltype
来查找其类型
这是不允许的。主要是因为无法“命名构造函数”。一个常见的用词不当是像
Name(0)
或 new Name(0)
这样的表达式调用构造函数。但事实并非如此
func(0)
。构造函数永远不会被我们直接调用,而是总是由需要生成新对象的语言构造间接调用。
[班级.ctor.将军]
1...构造函数没有名称。
2 构造函数用于初始化其类类型的对象。因为构造函数没有名称,所以在名称查找期间永远找不到它们;然而,使用函数符号([expr.type.conv])的显式类型转换将导致调用构造函数来初始化对象。 [注 1:语法看起来像是构造函数的显式调用。 — 尾注]
因为我们无法命名它们,所以我们无法使用像
这样的内省机制来检查它们。因此,该标准没有为构造函数指定“类型”,因为严格符合标准的程序无法检查所述类型。decltype
构造函数也不能拥有签名(如标准所定义),因为根据定义,签名包括函数名称(并且构造函数,如前所述,是无名的)。
[defns.signature.member]
签名C++ 中的构造函数有“类型”吗⟨类成员函数⟩名称、参数类型列表、函数所属的类、cv限定符(如果有)、ref限定符(如果有)和尾部requires子句(如果有)
是的,在 C++23 中,它们确实有类型,但在已发布的 C++20 中,它们没有类型,如下所述。这是由于CWG2479
的状态为
DRWP
来自dcl.fct在声明 T D 中,T 可以为空
,D 具有以下形式如果存在 Trailing-return-type,则 T 应为单个类型说明符 auto,U 为由 Trailing-return-type 指定的类型。
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt
派生声明符类型列表确定如下: * * 函数类型声明的返回类型U确定如下:否则,如果声明声明了转换函数,请参阅[class.conv.fct]。
- 否则,U就是T。 D 中 declarator-id 的类型是“parameter-type-list cv-qualifier-seqopt ref-qualifieropt 返回 U 的衍生声明符类型列表 noexceptopt 函数”,其中
- D 中 declarator-id 的类型为“parameter-type-list cv-qualifier-seqopt ref-qualifieropt 返回 U 的衍生声明符类型列表 noexceptopt 函数”,其中
the optional noexcept is present if and only if the exception specification ([except.spec]) is non-throwing.
可选的 attribute-specifier-seq 与函数类型相关。任一形式的类型都是函数类型。注意 C++23 中对 T 可能为空
的强调,这意味着现在构造函数具有类型。
C++20 在 C++20 中,来自
dcl.fct在声明 T D 中,其中 D 具有以下形式
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-type
任何一种形式的类型都是函数类型。这里注意
- (强调我的)
T
之前
CWG2476不允许为空类的构造函数永远不会被显式调用。您使用类似
new Name(5)
return
语句。
new Name(5)
返回的是对new
分配的内存的内存引用。这是通过如下语法给出的:Name * foo = new Name(5)
foo 是指向已分配的内容的指针,并且可以进行类型检查,因为
Name
引用类,而不是其构造函数。