Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is an explicitly deleted destructor implicitly marked constexpr?

Tags:

c++

c++20

When explicitly defaulting a destructor (e.g.: struct s { ~s() = default; };), it seems that the type can still be used in a constexpr context. However, when explicitly deleting a destructor (e.g.: struct s { ~s() = delete; };), Clang no longer thinks the type is viable for a constexpr context. So, as the title suggests, can a type with an explicitly deleted destructor still be used in a constexpr context?

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>{}));

The error produced by Clang 16.0.0 and 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
           ^

Live example

like image 402
303 Avatar asked Sep 03 '25 13:09

303


1 Answers

For a class to be a literal type, all you need is a constexpr destructor. = deleted functions have been allowed to be constexpr for a long time.

However, if you don't mark it constexpr, then it isn't constexpr except defaulted destructors which have an extra rule ([class.dtor]p9):

A defaulted destructor is a constexpr destructor if it satisfies the requirements for a constexpr destructor ([dcl.constexpr]).

Which a class with no members does, so ~a() = default; is constexpr.
~c() = delete; isn't constexpr because there's no reason for it to be. constexpr ~f() = delete; is constexpr because it's marked constexpr.

Clang is correct here: ~s() = delete; would not be constexpr if it is not specified to be, so can't be used as a literal type. It seems that std::is_literal_v<c> passes in gcc erroneously.

like image 129
Artyer Avatar answered Sep 05 '25 07:09

Artyer