构造函数有“类型”吗,因为它是一个特殊的成员函数?

问题描述 投票:0回答:3

我最近了解到构造函数没有名字。我还知道函数有一种称为“函数类型”的类型。例如, void func(int) { }

在上面的代码片段中,
func

具有

函数类型
void (int)
现在,既然构造函数是特殊的成员函数,那么它们是否也有像上面所示的类型呢?例如,假设我们有:

struct Name { Name(int) { } };

上面所示的构造函数是否也像普通函数或普通成员函数一样具有
函数类型

?如果是,那么我们如何找到该类型呢?是否允许在构造函数上使用 decltype 来查找其类型,就像对普通函数所做的那样?

    

c++ function types constructor language-lawyer
3个回答
6
投票
是否允许在构造函数上使用
decltype

来查找其类型


这是不允许的。主要是因为无法“命名构造函数”。一个常见的用词不当是像
Name(0)

new Name(0) 这样的表达式调用构造函数。但事实并非如此

func(0)
。构造函数永远不会被我们直接调用,而是总是由需要生成新对象的语言构造间接调用。

[班级.ctor.将军]

1

...构造函数没有名称。

2 构造函数用于初始化其类类型的对象。因为构造函数没有名称,所以在名称查找期间永远找不到它们;然而,使用函数符号([expr.type.conv])的显式类型转换将导致调用构造函数来初始化对象。 [注 1:语法看起来像是构造函数的显式调用。 — 尾注]

因为我们无法命名它们,所以我们无法使用像decltype

这样的内省机制来检查它们。因此,该标准没有为构造函数指定“类型”,因为严格符合标准的程序无法检查所述类型。

构造函数也不能拥有签名(如标准所定义),因为根据定义,签名包括函数名称(并且构造函数,如前所述,是无名的)。


[defns.signature.member]

签名

⟨类成员函数⟩名称、参数类型列表、函数所属的类、cv限定符(如果有)、ref限定符(如果有)和尾部requires子句(如果有)

C++ 中的构造函数有“类型”吗

1
投票
这是

CWG2476

,其状态为
DRWP

(意味着已在 C++26 工作草案中接受),这也使得构造函数具有类型。注意已发布

c++23
不允许构造函数具有类型: C++23 这里

T

中的

T D

不允许为空,这意味着 ctor 在已发布的 c++23 中没有类型。

来自
dcl.fct

在声明中

T D
,其中
    D
  1. 具有以下形式
    
    
     D1 ( parameter-declaration-clause ) cv-qualifier-seqopt
       ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt
    
在声明 T D 中,其中 D 具有以下形式

    D1 ( parameter-declaration-clause ) cv-qualifier-seqopt    ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-type
  1. 可选的 attribute-specifier-seq 属于函数类型。

任何一种形式的类型都是函数类型。

  1. 注意这里
  2. T
CWG2476

之前不允许为空,这意味着构造函数在c ++ 23中没有类型。


CWG2476

在 C++26 的
工作草案

中,

T

可以为空,这意味着现在构造函数确实有类型。

[
在 2024 年 3 月的会议上被接受为 DR

。]

9.3.4.6 [dcl.fct] 第 1 段的更改如下:

    在声明 T D
  1. 中,T 可以为空
  2. ,D 的形式为:

D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt noexcept-specifieropt attribute-specifier-seqopt trailing-return-typeopt

任何一种形式的类型都是函数类型

注意上面 CWG 中添加的对 T 可能为空

的强调,这意味着 ctor
Name::Name(int)

确实有一个类型。

    
类的构造函数永远不会被显式调用。您使用类似

new Name(5)

-3
投票
return

语句。

new Name(5)
返回的是对
new
分配的内存的内存引用。
这是通过如下语法给出的:
Name * foo = new Name(5)

foo 是指向已分配的内容的指针,并且可以进行类型检查,因为

Name
 引用类,而不是其构造函数。


© www.soinside.com 2019 - 2024. All rights reserved.