C++. The consexpr specifier. Differences between the constexpr specifier and const

The consexpr specifier. Differences between the constexpr specifier and const. Examples


Search other resources:


Contents


1. Specifier constexpr. Using for constants. Example

The constexpr specifier can be used:

  • for variables that need to be declared as constants (for constants);
  • for functions.

The general form of declaring a constant with the constexpr specifier is

constexpr type ConstantName = value_or_expression;

here

  • type – the type of the constant;
  • ConstantName – name of the constant;
  • value_or_expression – value (literal) or expression. A function can be called in an expression, also marked as constexpr.

In the case of defining constants for variables, this specifier specifies constants in the same way as the const specifier. However, the values of these constants must be determined at compile time, not generated later at run time. Such values that are defined immediately are literals (2.88, “Hello, world!”, true).

The general form of a function declaration with the constexpr specifier is as follows

constexpr return_type FuncName(list_of_parameters)
{
  // ...

  return const_expr_value;
}

where

  • FuncName – name of the function returning a constant;
  • list_of_parameters – list of function parameters;
  • const_expr_value is a value that can be calculated at compile time. This may be the result of calling other constexpr functions, the value of literals, the value of other constants declared with the constexpr specifier.

  

2. Differences between constexpr and const specifiers

There are the following differences between const and constexpr specifiers:

1. The initialization of a const variable can be delayed until runtime:

// Here sqrt() is evaluated later, when the program is executed
const double rc1 = sqrt(4.44 + c1);
cout << rc1 << endl;

2. The initialization of a constexpr variable cannot be delayed until runtime:

double ce1 = 23.2;
constexpr double rce1 = sqrt(2.88); // doesn't work because sqrt() is calculated later

3. The initialization of a constexpr variable can be calculated from another variable that is also declared constexpr

// 1. Initializing a constexpr constant based on another constexpr constant
constexpr int ce1 = 50;
constexpr int ce2 = ce1 * 2 + 100; // ce2 = 200 - it works

also based on a constant that is declared as const

// Attempt to initialize a constexpr constant
// based on another constant declared as const
const int c1 = 200;
constexpr int ce3 = c1 + 10; // works because the value of c1 is known at compile time

4. A constant of type const can be declared based on a variable, but a constant of type constexpr cannot

// Trying to initialize a const constant based on a variable
int v1 = 100;
const int c2 = v1 * 3; // it works

// Trying to initialize a constexpr constant based on a variable
int v2 = 100;
constexpr int ce4 = v2 * 3; // error, to fix this you need to declare v2 as constexpr

  

3. Specifier constexpr. Use for constants. Example

 

// constexpr variables can be initialized with a literal value,
// since the value of the literal is immediately defined
constexpr double d = true;
constexpr double t{ 3.05 };

cout << d << endl;

// constexpr float x = exp(2.8); // error
const float x = exp(2.8); // it works

double f = 0.0;
//constexpr double v = f + 2.5; // error, f is not a constexpr

// The initialization of a const variable can be delayed until runtime.

// 1. For constants (const) it all works
double c1 = 23.2;

// Here sqrt() is evaluated later, when the program is executed.
const double rc1 = sqrt(4.44 + c1);
cout << rc1 << endl;

// 2. For constexpr constants, this does not work,
// i.e. the initialization of a constexpr variable
// cannot be delayed until runtime. This initialization
// must be done immediately, otherwise the compiler will throw an error.
double ce1 = 23.2;
constexpr double rce1 = sqrt(2.88); // this doesn't work because sqrt() will be calculated later

constexpr double rce2 = sqrt(ce1); // it doesn't work

constexpr double ce2 = 3.8;
constexpr double rce3 = sqrt(ce2); // it doesn't work

  

4. Specifier constexpr. The use for functions returning a constant. Example

Example.

#include <iostream>
using namespace std;

// Constexpr and const variables must have an initializer.

// A function that returns the number 10
int GetNumber10()
{
  return 10;
}

// Another function that returns 20
constexpr int GetNumber20()
{
  return 20;
}

void TestVariable()
{
  // The initialization of a const variable can be delayed until runtime.

  // 1. For constants (const) it all works
  double c1 = 23.2;

  // Here sqrt() is evaluated later, when the program is executed.
  const double rc1 = sqrt(4.44 + c1);
  cout << rc1 << endl;

  // 2. For constexpr constants, this does not work,
  //    i.e. constexpr initialization cannot be delayed until runtime.
  // This initialization must be done right away or the compiler will throw an error.
  double ce1 = 23.2;
  //constexpr double rce1 = sqrt(2.88); // this doesn't work because sqrt() will be calculated later

  //constexpr double rce2 = sqrt(ce1); // this doesn't work
  constexpr double ce2 = 3.8;
  // constexpr double rce3 = sqrt(ce2); // this doesn't work
}

void main()
{
  // Calling the function

  // 1. Specifier const
  // Works here as the value will be fetched at run time.
  const int c1 = GetNumber10();

  // It also works here, but with a warning to mark c2 as constexpr.
  const int c2 = GetNumber20();
  cout << c2;

  // 2. Specifier cosnexpr
  // This doesn't work because the constexpr value must be obtained at compile time, not at run time.
  // constexpr int ce1 = GetNumber10();

  // Works because the GetNumber20() function is seen as such that calling it
  // and returning a value must be done at compile time.
  constexpr int ce2 = GetNumber20();
  cout << ce2 << endl;
}

  

5. Constexpr constant declarations based on other constants and literals. Example

 

// 1. Initialization of a constexpr constant based on another constexpr constant
constexpr int ce1 = 50;
constexpr int ce2 = ce1 * 2 + 100; // ce2 = 200 - it works

// 2. An attempt was made to initialize a constexpr constant based on another constant declared as const
const int c1 = 200;
constexpr int ce3 = c1 + 10; // this works because the value of c1 is known at compile time

// 3. Attempt to initialize const constant based on variable
int v1 = 100;
const int c2 = v1 * 3; // it works

// 4. Trying to initialize a constexpr constant based on a variable
int v2 = 100;
constexpr int ce4 = v2 * 3; // error, to fix this you need to declare v2 as constexpr

  

6. An example of calling another constexpr function from a constexpr function. Chain of calls

 

#include <iostream>
using namespace std;

// Function that returns the number 15
constexpr int GetNumber15()
{
  return 15;
}

// Another constexpr function that returns 20.
// This function calls the GetNumber15() function
constexpr int GetNumber20()
{
  return 5 + GetNumber15();
}

void main()
{
  // 1. Initializing a constexpr constant based on another constexpr constant
  constexpr int ce1 = 50;
  constexpr int ce2 = ce1 * 2 + 100; // ce2 = 200

  // 2. Attempt to initialize a constexpr constant based on another constant declared as const
  const int c1 = 200;
  constexpr int ce3 = c1 + 10; // works because the value of c1 is known at compile time

  // 3. Trying to initialize a const constant based on a variable
  int v1 = 100;
  const int c2 = v1 * 3; // +

  // 4. Trying to initialize a constexpr constant based on a variable
  int v2 = 100;
  //constexpr int ce4 = v2 * 3; // error, to fix this you need to declare v2 as constexpr

  // Calling the GetNumber20() function to initialize the constexpr constant named d1
  constexpr double d1 = GetNumber20(); // 20
  cout <&lt; d1 << endl;
}

  


Related topics