提问者:小点点

显式删除的析构函数是否隐式标记为 constexpr?


当显式默认析构函数时(例如:struct s { ~s() = default; };),似乎该类型仍然可以在 constexpr 上下文中使用。但是,当显式删除析构函数时(例如:struct s { ~s() = delete; };),Clang 不再认为该类型对于 constexpr 上下文是可行的。那么,正如标题所暗示的那样,具有显式删除析构函数的类型仍然可以在 constexpr 上下文中使用吗?

struct a { ~a() = default; };           // all ok
struct b { ~b(){} };                    // all fail
struct c { ~c() = delete; };            // fails on clang
struct d { constexpr ~d() = default; }; // all ok
struct e { constexpr ~e(){} };          // all ok
struct f { constexpr ~f() = delete; };  // all ok

static_assert(noexcept([]<c>{}));

16.0.0和Clang trunk产生的错误:

<source>:9:28: error: non-type template parameter has non-literal type 'c'
static_assert(noexcept([]<c>{}));
                           ^
<source>:3:12: note: 'c' is not literal because its destructor is not constexpr
struct c { ~c() = delete; };            // fails on clang
           ^

活生生的例子


共2个答案

匿名用户

对于一个文字类型的类,您只需要一个Constexpr析构函数。=deleted个函数长期以来一直被允许为Constexpr

但是,如果你不将其标记为constexpr,那么它不是constexpr,除了具有额外规则的默认析构函数([class.dtor]p9):

默认析构函数是 constexpr 析构函数,如果它满足 constexpr 析构函数 ([dcl.constexpr]) 的要求。

一个没有成员的类会这样做,所以~a()=默认值是常量表达式
~c()=删除不是constexpr,因为没有理由这样做。constexpr~f()=删除是constexpr,因为它被标记为<code>constexpr</code>。

Clang在这里是正确的:~s() = delete;如果未指定为,则不会是constexpr,因此不能用作文字类型。似乎标准::is_literal_v

匿名用户

每个 cpp 首选项:

https://en.cppreference.com/w/cpp/language/constexpr

constexpr变量

Constexpr变量必须满足以下要求:

> <李> < p >...

(从C 20开始)它必须具有持续的破坏,即:

  • 它不是类类型,也不是(可能是多维)数组,或者
  • 它是类类型
  • 或其(可能是多维)数组,该类类型具有 constexpr 析构函数,并且对于唯一效果是破坏对象的假设表达式 e,如果对象的生存期及其不可变子对象(但不是其可变子对象)的生存期被认为是在 E 内开始的,则 E 将是一个核心常量表达式。

constexpr析构函数

(直到C 20)析构函数不能是constexpr,但可以在常量表达式中隐式调用普通析构函数。

(C 20起)函数体不是=delete;必须满足以下附加要求:

    < li >每个用于销毁非静态数据成员和基类的析构函数都必须是constexpr析构函数。