Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a destructor be marked constexpr?

In C++, you can declare many things as constexpr: variables, functions (including member functions and operators), constructors, and since C++1z, also if statements and lambda expressions. However, declaring a destructor constexpr results in an error:

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

My questions:

  1. Why can't a destructor be marked constexpr?
  2. If I do not provide a destructor, is the implicitly generated destructor constexpr?
  3. If I declare a defaulted destructor (~X() = default;), is it automatically constexpr?
like image 985
s3rvac Avatar asked Jul 13 '17 05:07

s3rvac


People also ask

Can a constructor be constexpr?

A constructor that is declared with a constexpr specifier is a constexpr constructor. Previously, only expressions of built-in types could be valid constant expressions. With constexpr constructors, objects of user-defined types can be included in valid constant expressions.

What is constexpr in C ++ 11?

The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors.

How do I know if a function is constexpr?

The easiest way to check whether a function (e.g., foo ) is constexpr is to assign its return value to a constexpr as below: constexpr auto i = foo(); if the returned value is not constexpr compilation will fail.

Are default constructors constexpr?

For types with trivial default constructors, default initialization does not compile in constexpr.


2 Answers

As per the draft basic.types#10 possibly cv-qualified class type that has all of the following properties:

A possibly cv-qualified class type that has all of the following properties:

(10.5.1) - it has a trivial destructor,

(10.5.2) - it is either a closure type, an aggregate type, or has at least one constexpr constructor or constructor template (possibly inherited from a base class) that is not a copy or move constructor,

(10.5.3) - if it is a union, at least one of its non-static data members is of non-volatile literal type

(10.5.4) - if it is not a union, all of its non-static data members and base classes are of non-volatile literal types.

Ques 1: Why a destructor cannot be marked as constexpr?

Because only trivial destructors are qualified for constexpr Following is the relevant section of the draft

A destructor is trivial if it is not user-provided and if:

(5.4) — the destructor is not virtual,

(5.5) — all of the direct base classes of its class have trivial destructors, and

(5.6) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.

Otherwise, the destructor is non-trivial.

Ques 2: If I do not provide a destructor, is the implicitly generated destructor constexpr?

Yes, because implicitly generated destructor is trivial type, so it is qualified for constexpr

Ques 3: If I declare a defaulted destructor (~X() = default;), is it automatically constexpr?

Indeed, this destructor is user-declared and implicitly-generated and thus it is qualified for constexpr.


I'm not able to find any direct reference that only trivial destructors are qualified for constexpr but if the destructor is not trivial then it is for sure that class type is not cv-qualified. So it kind of implicit as you can't define a destructor for cv-qualified class.


C++20 Update

Since C++20, user defined destructors can also be constexpr under certain conditions.

dcl.constexpr/3:

The definition of a constexpr function shall satisfy the following requirements:

  • its return type (if any) shall be a literal type;
  • each of its parameter types shall be a literal type;
  • it shall not be a coroutine ([dcl.fct.def.coroutine]);
  • if the function is a constructor or destructor, its class shall not have any virtual base classes;
  • its function-body shall not enclose ([stmt.pre])
    • a goto statement,
    • an identifier label ([stmt.label]),
    • a definition of a variable of non-literal type or of static or thread storage duration.
like image 142
Hemant Gangwar Avatar answered Sep 30 '22 06:09

Hemant Gangwar


If what you're looking for is reasoning behind the restriction, have a look at this paper which clearly states that the restriction is artificial - there is no intrinsic property of destructors that prevent them from working in constexpr contexts, and indeed compiler implementors agree that supporting them in constexpr contexts will be trivial to implement.

I guess the C++ standards committee originally placed the restriction in C++11 because they didn't want to deal with destructors at that time and it was easier to just rule them out entirely.

like image 38
saarraz1 Avatar answered Sep 30 '22 07:09

saarraz1