为什么不能将析构函数标记为constexpr?

时间:2017-07-13 05:12:03

标签: c++ language-lawyer constexpr

在C ++中,您可以将许多内容声明为constexpr:变量,函数(包括成员函数和运算符),构造函数,以及自C ++ 1z以来if statementslambda expressions 。但是,声明destructor constexpr会导致错误:

struct X {
    constexpr ~X() = default; // error: a destructor cannot be 'constexpr'
};

我的问题:

  1. 为什么不能将析构函数标记为constexpr
  2. 如果我不提供析构函数,是隐式生成的析构函数constexpr吗?
  3. 如果我宣布默认的析构函数(~X() = default;),它会自动constexpr吗?

6 个答案:

答案 0 :(得分:11)

根据draft basic.types#10可能具有以下所有属性的cv限定类类型:

  

可能具有cv限定的类类型,它具有以下所有属性:

     

(10.5.1) - 它有一个简单的析构函数,

     

(10.5.2) - 它是闭包类型,聚合类型或者有   至少一个constexpr构造函数或构造函数模板(可能   继承自基类),它不是复制或移动构造函数,

     

(10.5.3) - 如果它是一个联合,至少有一个非静态数据   成员是非易失性文字类型

     

(10.5.4) - 如果不是   一个union,它的所有非静态数据成员和基类都是   非易失性文字类型。

问题1:为什么析构函数不能被标记为constexpr?

因为只有琐碎的析构函数才有资格获得constexpr 以下是draft

的相关部分
  

如果析构函数不是用户提供的,并且如果:

,则析构函数很简单      

(5.4) - 析构函数不是虚拟的,

     

(5.5) - 其类的所有直接基类都很简单   析构函数,

     

(5.6) - 对于其类的所有非静态数据成员   对于类类型(或其数组),每个这样的类都是微不足道的   析构函数。

     

否则,析构函数是非常重要的。

问题2:如果我不提供析构函数,是隐式生成的析构函数constexpr吗?

是的,因为隐式生成的析构函数是微不足道的类型,所以它有资格用于constexpr

问题3:如果我声明一个默认的析构函数(~X()= default;),它会自动constexpr吗?

实际上,这个析构函数是用户声明的并且是隐式生成的,因此它符合constexpr的条件。

我无法找到任何直接引用,只有琐碎的destructors符合constexpr的条件,但如果析构函数不是微不足道的话,那么确定类类型不是{{1}所以它是隐含的,因为你无法为cv-qualified.类定义destructor

答案 1 :(得分:4)

如果您正在寻找的是限制背后的推理,请查看this paper明确指出限制是人为的 - 析构函数的内在属性无法阻止他们在constexpr上下文中工作,实际上编译器实现者同意在constexpr上下文中支持它们将很容易实现

我猜C ++标准委员会最初将限制放在C ++ 11中,因为他们当时并不想处理析构函数,而且更容易完全排除它们。

答案 2 :(得分:3)

  

为什么析构函数不能被标记为constexpr?

C ++ 11标准特别针对使用const构造和非静态成员函数。它没有说出任何关于析构函数的具体内容。可以假设析构函数将被视为非静态成员函数。

const只能用于constexpr成员函数。由于析构函数不能是constexpr成员函数,因此无法将其限定为constexpr ~X() = default; 成员函数。

  

如果我不提供析构函数,则是隐式生成的析构函数constexpr

使用

~X() = default;

是一个错误,我觉得编译器生成的析构函数不是constexpr函数。我无法在标准中找到任何证据来证明我的陈述。我猜。

  

如果我声明了默认的析构函数(struct X { constexpr X(int i) : i_(i) {} ~X() = default; int i_; }; int main() { const X x(10); } ),它会自动EditText

我想不是。再一次,我无法在标准中找到任何证据来证明我的陈述。我猜。

FWIW,g ++编译并构建以下程序就好了。

EditText

答案 3 :(得分:3)

从C ++ 20开始,可以将构造函数标记为constexpr;我不知道它是否在任何地方都明确表示“析构函数可能是constexpr”,但是draft standard在第9.2.5节第5段中包含以下文本:

其函数体不是constexpr的{​​{1}}析构函数的定义还应满足 以下要求:

  • 对于类类型或其(可能是多维)数组的每个子对象,该类类型应 有一个constexpr析构函数。

这现在也具有有用的功能,因为C ++ 20还允许在= delete上下文中使用newdelete,从而允许constexprvector之类的东西可以在没有黑客的情况下在编译时工作(尽管我相信C ++ 20实际上并未包括对标准库的更改以允许这样做,但是可以使用与string相同的API和行为来实现某些功能,这些功能可以完全正常工作在编译时)。

答案 4 :(得分:2)

析构函数不能是constexpr,因为constexpr函数不能有副作用,根据定义,析构函数只能通过副作用使用。简而言之,拥有constexpr的析构函数是没用的。

如果对象的析构函数不重要,则该对象不能为constexpr。默认情况下,默认值为constexpr

Live

来自[class.dtor]

  

析构函数声明(如果有)的decl-specifier-seq的每个decl-specifier应为friendinlinevirtual

遗漏了constexpr。所以你可以把它当作:因为标准说的是 TM

答案 5 :(得分:2)

Reference的标记:' s:

  

constexpr析构函数

     

在大多数情况下,为了在常量中创建类型T的对象   表达,T的破坏必须是微不足道的。但是,非平凡   析构函数是现代C ++的重要组成部分,部分原因在于   RAII习语的广泛使用,也适用于   constexpr评估。可以支持非平凡的析构函数   常量表达式,如下:

     
      
  • 允许将析构函数标记为constexpr
  •   
  • 如果他们只调用constexpr析构函数,则使默认析构函数成为constexpr
  •   
  • 对于constexpr变量,要求评估析构函数是一个常量表达式(除了被销毁的对象可能是   在自己的析构函数中修改
  •   
     

但是,对于这样的功能,没有引人注目的用例,并且   将会有一个非常重要的实施成本确保这一点   析构函数在适当的时间运行。