C++. Спецификатор constexpr. Отличия спецификатора constexpr от const. Примеры

Спецификатор constexpr. Отличия спецификатора constexpr от const. Примеры


Поиск на других ресурсах:

 


Содержание


1. Спецификатор constexpr. Применение для констант. Пример

Специфікатор constexpr може застосовуватись:

  • для переменных, которые нужно объявить как константы (для констант);
  • для функций.

Общая форма объявления константы со спецификатором constexpr имеет вид

constexpr type ConstantName = value_or_expression;

здесь

  • type – тип константы;
  • ConstantName – имя константы;
  • value_or_expression – значение (литерал) или выражение. В выражении может вызываться функция, отмеченная также как constexpr.

В случае определения для переменных констант, этот спецификатор задает константы так же как и спецификатор const. Однако значения этих констант должны быть определены на этапе компиляции, а не сформированы позже на этапе выполнения. Такие значения, которые определены сразу есть литералами (2.88, «Hello, world!», true).

Общая форма объявления функции со спецификатором constexpr следующая

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

  return const_expr_value;
}

здесь

  • FuncName – имя функции, возвращающей константу;
  • list_of_parameters – список параметров функции;
  • const_expr_value – значение, которое может рассчитываться на этапе компиляции. Это может быть результат вызова других constexpr-функций, значение литералов, значение других констант, объявленных со спецификатором constexpr.

 

2. Различия между спецификаторами constexpr и const

Между спецификаторами const и constexpr есть следующие отличия:

1. Инициализация переменной const может быть отложена до времени выполнения:

// Здесь sqrt() вычисляется позже, при выполнении программы
const double rc1 = sqrt(4.44 + c1);
cout << rc1 << endl;

2. Инициализация переменной constexpr не может быть отложена до времени выполнения:

double ce1 = 23.2;
constexpr double rce1 = sqrt(2.88); // не работает, поскольку sqrt() вычисляется позже

3. Инициализацию переменной constexpr можно вычислять на основе другой переменной, которая также объявлена как constexpr.

// 1. Инициализация константы constexpr на основе другой константы constexpr
constexpr int ce1 = 50;
constexpr int ce2 = ce1 * 2 + 100; // ce2 = 200 - работает

также на основе константы, которая объявлена как const

// Попытка инициализации константы constexpr
// на основе другой константы, объявленной как const
const int c1 = 200;
constexpr int ce3 = c1 + 10;  // работает, поскольку значение c1 известно на этапе компиляции

4. Константу типа const можно объявлять на основе переменной, а константу типа constexpr нельзя

// Попытка инициализации константы const на основе переменной
int v1 = 100;
const int c2 = v1 * 3; // работает

// Попытка инициализации константы constexpr на основе переменной
int v2 = 100;
constexpr int ce4 = v2 * 3; // ошибка, чтобы исправить это нужно v2 объявить как constexpr

 

3. Спецификатор constexpr. Применение для констант. Пример
// Переменные constexpr допускается инициализировать значением литерала,
// поскольку значение литерала сразу определено
constexpr double d = true;
constexpr double t{ 3.05 };

cout << d << endl;

// constexpr float x = exp(2.8); // ошибка
const float x = exp(2.8); // работает

double f = 0.0;
//constexpr double v = f + 2.5; // ошибка, f не есть constexpr

// Инициализация переменной const может быть отложена до времени выполнения.

// 1. Для констант (const) это все работает
double c1 = 23.2;

// Здесь sqrt() вычисляется позже, при выполнении программы
const double rc1 = sqrt(4.44 + c1);
cout << rc1 << endl;

// 2. Для констант constexpr это не работает,
// то есть инициализация переменной constexpr не может
// быть отложена до времени выполнения.
// Эта инициализация должна выполняться сразу,
// иначе компилятор выдаст ошибку.
double ce1 = 23.2;
constexpr double rce1 = sqrt(2.88); // не работает, поскольку sqrt() будет вычислено позже

constexpr double rce2 = sqrt(ce1); // не работает

constexpr double ce2 = 3.8;
constexpr double rce3 = sqrt(ce2); // не работает

 

4. Спецификатор constexpr. Применение для возвращающих константу функций. Пример

Пример.

#include <iostream>
using namespace std;

// Для переменных constexpr и const обязательно должен быть инициализатор.

// Функция, возвращающая число 10
int GetNumber10()
{
  return 10;
}

// Другая функция, возвращающая 20
constexpr int GetNumber20()
{
  return 20;
}

void TestVariable()
{
  // Инициализация переменной const может быть отложена до времени выполнения.

  // 1. Для констант (const) это все работает
  double c1 = 23.2;

  // Здесь sqrt() вычисляется позже, при выполнении программы.
  const double rc1 = sqrt(4.44 + c1);
  cout << rc1 << endl;

  // 2. Для констант constexpr это не работает,
  // тоесть инициализация constexpr не может
  // быть отложена до времени выполнения.
  // Эта инициализация должна выполняться сразу,
  // иначе компилятор выдаст ошибку.
  double ce1 = 23.2;
  //constexpr double rce1 = sqrt(2.88); // не работает, поскольку sqrt() будет вычислено позже

  //constexpr double rce2 = sqrt(ce1); // не работает
  constexpr double ce2 = 3.8;
  //constexpr double rce3 = sqrt(ce2); // не работает
}

void main()
{
  // Вызов функции

  // 1. Спецификатор const
  // Здесь работает, поскольку значение будет получено на этапе выполнения.
  const int c1 = GetNumber10();

  // Здесь также работает, но с предупреждением пометить c2 как constexpr
  const int c2 = GetNumber20();
  cout << c2;

  // 2. Спецификатор cosnexpr
  // Не работает, поскольку constexpr-значение должно получаться
  // на этапе компиляции, а не на этапе выполнения
  // constexpr int ce1 = GetNumber10();

  // Работает, поскольку функция GetNumber20() замечена как таковая,
  // что ее вызов и возврат значения должны выполняться на этапе компиляции
  constexpr int ce2 = GetNumber20();
  cout << ce2 << endl;
}

 

5. Объявления констант constexpr на основе других констант и литералов. Пример

 

// 1. Инициализация константы constexpr на основе другой константы constexpr
constexpr int ce1 = 50;
constexpr int ce2 = ce1 * 2 + 100; // ce2 = 200 - работает

// 2. Попытка инициализации константы constexpr
// на основе другой константы, объявленной как const
const int c1 = 200;
constexpr int ce3 = c1 + 10; // работает, поскольку значение c1 известно на этапе компиляции

// 3. Попытка инициализации константы const на основе переменной
int v1 = 100;
const int c2 = v1 * 3; // работает

// 4. Попытка инициализации константы constexpr на основе переменной
int v2 = 100;
constexpr int ce4 = v2 * 3; // ошибка, чтобы исправить это нужно v2 объявить как constexpr

 

6. Пример вызова из constexpr-функции другой constexpr-функции. Цепочка вызовов

 

#include <iostream>
using namespace std;

// Функция, которая возвращает число 15
constexpr int GetNumber15()
{
  return 15;
}

// Другая constexpr-функция, которая возвращает 20.
// Эта функция обращается к функции GetNumber15()
constexpr int GetNumber20()
{
  return 5 + GetNumber15();
}

void main()
{
  // 1. Инициализация константы constexpr на основе другой константы constexpr
  constexpr int ce1 = 50;
  constexpr int ce2 = ce1 * 2 + 100; // ce2 = 200

  // 2. Попытка инициализации константы constexpr на основе другой константы, объявленной как const
  const int c1 = 200;
  constexpr int ce3 = c1 + 10; // работает, поскольку значение c1 известно на этапе компиляции

  // 3. Попытка инициализации константы const на основе переменной
  int v1 = 100;
  const int c2 = v1 * 3; // работает

  // 4. Попытка инициализации константы constexpr на основе переменной
  int v2 = 100;
  //constexpr int ce4 = v2 * 3; // ошибка, чтобы исправить это нужно v2 объявить как constexpr

  // Вызов функции GetNumber20() для инициализации constexpr-константы с именем d1
  constexpr double d1 = GetNumber20(); // 20 - работает
  cout << d1 << endl;
}

 


Связанные темы