const против constexpr по переменным

Есть ли разница между следующими определениями?

const     double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;

Если нет, какой стиль предпочтительнее в C++11?

6 ответов

Решение

Я считаю, что есть разница. Давайте переименуем их, чтобы нам было легче говорить о них:

const     double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;

И то и другое PI1 а также PI2 являются постоянными, то есть вы не можете изменить их. Однако только PI2 является константой времени компиляции. Он должен быть инициализирован во время компиляции. PI1 может быть инициализирован во время компиляции или во время выполнения. Кроме того, только PI2 может использоваться в контексте, который требует константы времени компиляции. Например:

constexpr double PI3 = PI1;  // error

но:

constexpr double PI3 = PI2;  // ok

а также:

static_assert(PI1 == 3.141592653589793, "");  // error

но:

static_assert(PI2 == 3.141592653589793, "");  // ok

Что вы должны использовать? Используйте то, что соответствует вашим потребностям. Вы хотите убедиться, что у вас есть постоянная времени компиляции, которую можно использовать в тех случаях, когда требуется постоянная времени компиляции? Вы хотите иметь возможность инициализировать его вычислением, выполненным во время выполнения? И т.п.

Здесь нет разницы, но это важно, когда у вас есть тип, у которого есть конструктор.

struct S {
    constexpr S(int);
};

const S s0(0);
constexpr S s1(1);

s0 является константой, но она не обещает быть инициализированной во время компиляции. s1 отмечен constexpr, так что это константа и, потому что Sконструктор также отмечен constexpr, он будет инициализирован во время компиляции.

В основном это имеет значение, когда инициализация во время выполнения занимает много времени, и вы хотите перенести эту работу на компилятор, где это также занимает много времени, но не замедляет время выполнения скомпилированной программы

constexpr указывает значение, которое является постоянным и известно во время компиляции.
const указывает значение, которое является только постоянным; это не обязательно знать во время компиляции.

int sz;
constexpr auto arraySize1 = sz;    // error! sz's value unknown at compilation
std::array<int, sz> data1;         // error! same problem

constexpr auto arraySize2 = 10;    // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

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

int sz;
const auto arraySize = sz;       // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation

Все объекты constexpr являются const, но не все объекты const являются constexpr.

Если вы хотите, чтобы компиляторы гарантировали, что переменная имеет значение, которое может быть использовано в контекстах, требующих констант времени компиляции, инструмент для достижения - constexpr, а не const.

Символической константе constexpr должно быть присвоено значение, известное во время компиляции. Например:

constexpr int max = 100; 
void use(int n)
{
    constexpr int c1 = max+7; // OK: c1 is 107
    constexpr int c2 = n+7;   // Error: we don’t know the value of c2
    // ...
}

Для обработки случаев, когда значение "переменной" инициализируется значением, которое не известно во время компиляции, но никогда не изменяется после инициализации, C++ предлагает вторую форму константы (const). Например:

constexpr int max = 100; 
void use(int n)
{
    constexpr int c1 = max+7; // OK: c1 is 107
    const int c2 = n+7; // OK, but don’t try to change the value of c2
    // ...
    c2 = 7; // error: c2 is a const
}

Такие "постоянные переменные" очень распространены по двум причинам:

  1. В C++98 не было constexpr, поэтому люди использовали const.
  2. Элемент списка "Переменные", которые не являются константными выражениями (их значение не известно во время компиляции), но не изменяют значения после инициализации, сами по себе широко используются.

Ссылка: "Программирование: принципы и практика с использованием C++" от Страуструпа

Еще один пример, чтобы понять разницу между constа также constexp.

      int main()
{
    int n;
    cin >> n;               

    const int c = n;        // OK: 'c' can also be initialized at run time
    constexpr int e = n;    // Error: 'e' must be initialized at compile time
}

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

      constexpr int add(int a, int b)
{
    return a + b;
};


int main()
{
    int n = add(4, 3);          // may or may not be computed at compile time
    constexpr int m = add(4,3); // must be computed at compile time
}

constexpr -> Используется для постоянной времени компиляции. Это в основном используется для оптимизации времени выполнения.
const -> Используется для постоянной времени выполнения.

Другие вопросы по тегам