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
For a class to be a literal type, all you need is a constexpr
destructor. = delete
d 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With