Разница между `constexpr` и` const`

593

Какая разница между constexprа const?

  • Когда я могу использовать только один из них?
  • Когда я могу использовать оба и как выбрать один?
MBZ
источник
71
constexprсоздает постоянную времени компиляции; constпросто означает, что значение не может быть изменено.
0x499602D2
Может быть, эта статья из boost/hanaбиблиотеки может рассказать о некоторых constexprпроблемах, которые вы можете использовать, constexprа где нет: boost.org/doc/libs/1_69_0/libs/hana/doc/html/…
Andry
@ 0x499602D2 « просто означает, что значение не может быть изменено ». Для скаляра, инициализированного литералом, значение, которое нельзя изменить , также является постоянной времени компиляции.
любопытный парень
@curiousguy Да, мой комментарий был очень упрощен. По общему признанию, я был constexpr
новичком

Ответы:

587

Основное значение и синтаксис

Оба ключевых слова могут быть использованы в объявлении объектов, а также функций. Основное отличие применительно к объектам заключается в следующем:

  • constобъявляет объект как константу . Это подразумевает гарантию того, что после инициализации значение этого объекта не изменится, и компилятор может использовать этот факт для оптимизации. Это также помогает запретить программисту писать код, который изменяет объекты, которые не должны были изменяться после инициализации.

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

Применительно к функциям основное отличие заключается в следующем:

  • constможет использоваться только для нестатических функций-членов, но не для функций в целом. Это дает гарантию, что функция-член не изменяет ни один из нестатических элементов данных.

  • constexprможет использоваться как с членами, так и с не членами, а также с конструкторами. Он объявляет функцию пригодной для использования в константных выражениях . Компилятор примет его, только если функция соответствует определенным критериям (7.1.5 / 3,4), наиболее важно (†) :

    • Тело функции должно быть не виртуальным и чрезвычайно простым: кроме определения типов и статических returnутверждений, допускается только один оператор. В случае конструктора разрешены только список инициализации, typedefs и static assert. ( = defaultи = deleteтоже разрешено.)
    • Начиная с C ++ 14, правила более смягчены, что разрешено с тех пор внутри функции constexpr: asmобъявление, gotoоператор, оператор с меткой, отличной от caseи default, try-block, определение переменной не-литерала тип, определение переменной статической или длительности хранения потока, определение переменной, для которой не выполняется инициализация.
    • Аргументы и возвращаемый тип должны быть литеральными типами (то есть, вообще говоря, очень простыми типами, обычно скалярами или агрегатами).

Постоянные выражения

Как сказано выше, constexprобъявляет оба объекта, а также функции, пригодные для использования в константных выражениях. Постоянное выражение не просто константа:

  • Он может использоваться в местах, где требуется оценка во время компиляции, например, параметры шаблона и спецификаторы размера массива:

    template<int N>
    class fixed_size_list
    { /*...*/ };
    
    fixed_size_list<X> mylist;  // X must be an integer constant expression
    
    int numbers[X];  // X must be an integer constant expression
  • Но обратите внимание:

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

    • Объект может быть пригоден для использования в константных выражениях без объявления constexpr. Пример:

      int main()
      {
        const int N = 3;
        int numbers[N] = {1, 2, 3};  // N is constant expression
      }

    Это возможно, потому что N, будучи постоянным и инициализированным во время объявления с литералом, удовлетворяет критериям для постоянного выражения, даже если оно не объявлено constexpr.

Так, когда я действительно должен использовать constexpr?

  • Объект , как Nвыше , может быть использован в качестве постоянного выражения , не объявляются constexpr. Это верно для всех объектов, которые:

    • const
    • целочисленного или перечислимого типа и
    • инициализируется во время объявления выражением, которое само является константным выражением

    [Это связано с §5.19 / 2: константное выражение не должно включать подвыражение, которое включает «модификацию lvalue-to-rvalue, если […] glvalue целочисленного или перечислимого типа […]» Спасибо Ричарду Смиту за исправление моего ранее утверждали, что это верно для всех литеральных типов.]

  • Чтобы функция была пригодна для использования в константных выражениях, она должна быть явно объявлена constexpr; недостаточно просто удовлетворять критериям для функций с постоянным выражением. Пример:

    template<int N>
    class list
    { };
    
    constexpr int sqr1(int arg)
    { return arg * arg; }
    
    int sqr2(int arg)
    { return arg * arg; }
    
    int main()
    {
      const int X = 2;
      list<sqr1(X)> mylist1;  // OK: sqr1 is constexpr
      list<sqr2(X)> mylist2;  // wrong: sqr2 is not constexpr
    }

Когда я могу / должен использовать оба, constи constexpr вместе?

А. В объявлениях объекта. Это никогда не требуется, когда оба ключевых слова ссылаются на один и тот же объект, который должен быть объявлен. constexprподразумевает const.

constexpr const int N = 5;

такой же как

constexpr int N = 5;

Однако обратите внимание, что могут быть ситуации, когда каждое ключевое слово ссылается на разные части объявления:

static constexpr int N = 3;

int main()
{
  constexpr const int *NP = &N;
}

Здесь NPобъявляется как адрес-константа-выражение, то есть указатель, который сам является константным выражением. (Это возможно , когда адрес генерируется путем применения оператора адреса к / глобальному выражению постоянная статическим.) Здесь, как constexprи constтребуется: constexprвсегда относится к выражению объявляются (здесь NP), в то время как constотносится к int(это объявляет pointer- к сопзЬ). Удаление constможет сделать выражение недопустимым (потому что (a) указатель на неконстантный объект не может быть константным выражением, а (b) &Nфактически является указателем на константу).

Б. В объявлениях функций-членов. В C ++ 11 constexprподразумевается const, а в C ++ 14 и C ++ 17 это не так. Функция-член, объявленная в C ++ 11 как

constexpr void f();

должен быть объявлен как

constexpr void f() const;

под C ++ 14, чтобы все еще быть пригодным для использования в качестве constфункции.

jogojapan
источник
3
ИМО «необязательно оценивать во время компиляции» менее полезно, чем думать о них как «оцениваемое во время компиляции». Ограничения для константного выражения означают, что компилятору будет относительно легко его оценить. Компилятор должен пожаловаться, если эти ограничения не выполняются. Поскольку побочных эффектов нет, вы никогда не сможете определить разницу, «оценивал» это компилятор или нет.
aschepler
10
@aschepler Конечно. Мое главное замечание заключается в том, что если вы вызываете constexprфункцию с неконстантным выражением, например с обычной переменной, это совершенно законно, и функция будет использоваться, как и любая другая функция. Он не будет оцениваться во время компиляции (потому что не может). Возможно, вы думаете, что это очевидно - но если бы я сказал, что функция, объявленная как constexpr, всегда будет оцениваться во время компиляции, она может быть неверно интерпретирована.
Джогоджапан
5
Да, я говорил об constexprобъектах, а не функциях. Мне нравится думать constexprоб объектах как о принудительной оценке значений времени компиляции, а constexprо функциях - как о том, что функция может быть оценена во время компиляции или во время выполнения в зависимости от ситуации.
aschepler
2
Исправление: «const» - это только ограничение, которое ВЫ не можете изменить значение переменной; он не дает никаких обещаний, что значение не изменится (т.е. кем-то другим). Это свойство записи, а не свойство чтения.
Джаред Грабб
3
Это предложение: оно дает гарантию, что функция-член не изменяет ни один из нестатических элементов данных. пропускает одну важную деталь Члены, помеченные как, mutableтакже могут быть изменены constфункциями-членами.
Всезнающий
119

constприменяется к переменным и предотвращает их изменение в вашем коде.

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

По сути, они представляют собой две разные концепции и могут (и должны) использоваться вместе.

Картик Т
источник
2
использование const & constexpr, например: en.cppreference.com/w/cpp/container/array/get
Манохар Редди Поредди
64

обзор

  • constгарантирует, что программа не изменяет значение объекта . Тем constне менее, не гарантирует, какой тип инициализации объект подвергается.

    Рассматривать:

    const int mx = numeric_limits<int>::max();  // OK: runtime initialization

    Функция max()просто возвращает буквальное значение. Однако, поскольку инициализатор является вызовом функции, он mxподвергается инициализации во время выполнения. Следовательно, вы не можете использовать его как константное выражение :

    int arr[mx];  // error: “constant expression required”
  • constexprэто новое ключевое слово C ++ 11, которое избавляет вас от необходимости создавать макросы и жестко закодированные литералы. Это также гарантирует, при определенных условиях, что объекты подвергаются статической инициализации . Он контролирует время оценки выражения. Обеспечивая оценку его выражения во время компиляции , constexprпозволяет вам определять истинные константные выражения, которые имеют решающее значение для критичных ко времени приложений, системного программирования, шаблонов и, вообще говоря, в любом коде, который опирается на константы времени компиляции.

Функции с постоянными выражениями

Функция с постоянным выражением - это объявленная функция constexpr. Его тело должно быть не виртуальным и состоять только из одного оператора return, кроме typedefs и static asserts. Его аргументы и возвращаемое значение должны иметь литеральные типы. Его можно использовать с аргументами без константных выражений, но когда это сделано, результат не является константным выражением.

Функция постоянного выражения предназначена для замены макросов и жестко закодированных литералов без ущерба для производительности или безопасности типов.

constexpr int max() { return INT_MAX; }           // OK
constexpr long long_max() { return 2147483647; }  // OK
constexpr bool get_val()
{
    bool res = false;
    return res;
}  // error: body is not just a return statement

constexpr int square(int x)
{ return x * x; }  // OK: compile-time evaluation only if x is a constant expression
const int res = square(5);  // OK: compile-time evaluation of square(5)
int y = getval();
int n = square(y);          // OK: runtime evaluation of square(y)

Объекты с постоянным выражением

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

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

struct S
{
    constexpr int two();      // constant-expression function
private:
    static constexpr int sz;  // constant-expression object
};
constexpr int S::sz = 256;
enum DataPacket
{
    Small = S::two(),  // error: S::two() called before it was defined
    Big = 1024
};
constexpr int S::two() { return sz*2; }
constexpr S s;
int arr[s.two()];  // OK: s.two() called after its definition

Константные выражения

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

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

struct complex
{
    // constant-expression constructor
    constexpr complex(double r, double i) : re(r), im(i) { }  // OK: empty body
    // constant-expression functions
    constexpr double real() { return re; }
    constexpr double imag() { return im; }
private:
    double re;
    double im;
};
constexpr complex COMP(0.0, 1.0);         // creates a literal complex
double x = 1.0;
constexpr complex cx1(x, 0);              // error: x is not a constant expression
const complex cx2(x, 1);                  // OK: runtime initialization
constexpr double xx = COMP.real();        // OK: compile-time initialization
constexpr double imaglval = COMP.imag();  // OK: compile-time initialization
complex cx3(2, 4.6);                      // OK: runtime initialization

Подсказки из книги Скотта Мейерса « Эффективное современное С ++ » о constexpr:

  • constexpr объекты являются постоянными и инициализируются значениями, известными во время компиляции;
  • constexpr функции выдают результаты времени компиляции при вызове с аргументами, значения которых известны во время компиляции;
  • constexprобъекты и функции могут использоваться в более широком диапазоне контекстов, чем не- constexprобъекты и функции;
  • constexpr является частью интерфейса объекта или функции.

Источник: Использование constexpr для улучшения безопасности, производительности и инкапсуляции в C ++ .

zangw
источник
Спасибо за отличный пример кода, показывающий различные ситуации. Как ни крути другие объяснения, я обнаружил, что просмотр кода в действии гораздо более полезен и понятен. Это действительно помогло укрепить мое понимание происходящего.
RTHarston
35

В соответствии с книгой Бьярна Страуструпа «Язык программирования C ++ 4-й редакции»
const : примерно означает «Я обещаю не менять это значение» (§7.5). Это используется главным образом для указания интерфейсов, так что данные могут передаваться функциям, не опасаясь их изменения.
Компилятор выполняет обещание, данное const.
constexpr : примерно означает «быть оцененным во время компиляции» (§10.4). Это используется в первую очередь для указания констант,
например:

const int dmv = 17; // dmv is a named constant
int var = 17; // var is not a constant
constexpr double max1 = 1.4*square(dmv); // OK if square(17) is a constant expression
constexpr double max2 = 1.4square(var); // error : var is not a constant expression
const double max3 = 1.4square(var); //OK, may be evaluated at run time
double sum(const vector<double>&); // sum will not modify its argument (§2.2.5)
vector<double> v {1.2, 3.4, 4.5}; // v is not a constant
const double s1 = sum(v); // OK: evaluated at run time
constexpr double s2 = sum(v); // error : sum(v) not constant expression

Чтобы функция могла использоваться в константном выражении, то есть в выражении, которое будет оцениваться компилятором, должно быть определено constexpr .
Например:

constexpr double square(double x) { return xx; }


Чтобы быть constexpr, функция должна быть довольно простой: просто оператор возврата, вычисляющий значение. Функция constexpr может использоваться для непостоянных аргументов, но когда это сделано, результат не является константным выражением. Мы разрешаем вызывать функцию constexpr с аргументами неконстантных выражений в контекстах, которые не требуют константных выражений, поэтому мы не должны определять по существу одну и ту же функцию дважды: один раз для константных выражений и один раз для переменных.
В некоторых местах константные выражения требуются правилами языка (например, границы массивов (§2.2.5, §7.3), метки case (§2.2.4, §9.4.2), некоторые аргументы шаблона (§25.2) и константы, объявленные с помощью constexpr). В других случаях оценка времени компиляции важна для производительности. Независимо от проблем производительности, понятие неизменности (объекта с неизменяемым состоянием) является важной проблемой проектирования (§10.4).

Мустафа Экичи
источник
Есть еще проблемы с производительностью. Кажется, что функция constexpr при оценке во время выполнения может работать медленнее, чем не-constexpr версия функции. Также, если у нас есть постоянное значение, мы должны предпочесть «const» или «constexpr»? (больше стиль, сгенерированный сборкой вопросов выглядит одинаково)
CoffeDeveloper
31

И то, constи другое constexprможно применять к переменным и функциям. Хотя они похожи друг на друга, на самом деле это очень разные понятия.

Оба constи constexprозначают, что их значения не могут быть изменены после их инициализации. Так, например:

const int x1=10;
constexpr int x2=10;

x1=20; // ERROR. Variable 'x1' can't be changed.
x2=20; // ERROR. Variable 'x2' can't be changed.

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

int temp=rand(); // temp is generated by the the random generator at runtime.

const int x1=10; // OK - known at compile time.
const int x2=temp; // OK - known only at runtime.
constexpr int x3=10; // OK - known at compile time.
constexpr int x4=temp; // ERROR. Compiler can't figure out the value of 'temp' variable at compile time so `constexpr` can't be applied here.

Основным преимуществом для того, чтобы знать, известно ли значение во время компиляции или во время выполнения, является тот факт, что константы времени компиляции могут использоваться всякий раз, когда необходимы константы времени компиляции. Например, C ++ не позволяет вам указывать C-массивы с переменной длиной.

int temp=rand(); // temp is generated by the the random generator at runtime.

int array1[10]; // OK.
int array2[temp]; // ERROR.

Итак, это означает, что:

const int size1=10; // OK - value known at compile time.
const int size2=temp; // OK - value known only at runtime.
constexpr int size3=10; // OK - value known at compile time.


int array3[size1]; // OK - size is known at compile time.
int array4[size2]; // ERROR - size is known only at runtime time.
int array5[size3]; // OK - size is known at compile time.

Таким образом, constпеременные могут определять как константы времени компиляции, подобные тем, size1которые можно использовать для указания размеров массива, так и константы времени выполнения, подобные size2тем, которые известны только во время выполнения и не могут использоваться для определения размеров массива. С другой стороны, constexprвсегда определяйте константы времени компиляции, которые могут указывать размеры массива.

И то, constи другое constexprможно применить и к функциям. constФункция должна быть функцией членом (метод, оператор) , где применением constключевого слова означает , что метод не может изменить значение их члена (не статический) полей. Например.

class test
{
   int x;

   void function1()
   {
      x=100; // OK.
   }

   void function2() const
   {
      x=100; // ERROR. The const methods can't change the values of object fields.
   }
};

А constexprэто другая концепция. Он отмечает функцию (член или не член) как функцию, которая может быть оценена во время компиляции, если в качестве аргументов переданы константы времени компиляции . Например, вы можете написать это.

constexpr int func_constexpr(int X, int Y)
{
    return(X*Y);
}

int func(int X, int Y)
{
    return(X*Y);
}

int array1[func_constexpr(10,20)]; // OK - func_constexpr() can be evaluated at compile time.
int array2[func(10,20)]; // ERROR - func() is not a constexpr function.

int array3[func_constexpr(10,rand())]; // ERROR - even though func_constexpr() is the 'constexpr' function, the expression 'constexpr(10,rand())' can't be evaluated at compile time.

Кстати, constexprфункции - это обычные функции C ++, которые можно вызывать, даже если переданы непостоянные аргументы. Но в этом случае вы получаете значения не-constexpr.

int value1=func_constexpr(10,rand()); // OK. value1 is non-constexpr value that is evaluated in runtime.
constexpr int value2=func_constexpr(10,rand()); // ERROR. value2 is constexpr and the expression func_constexpr(10,rand()) can't be evaluated at compile time.

constexprТакже может быть применено к функциям членов (методы), операторов и даже конструкторов. Например.

class test2
{
    static constexpr int function(int value)
    {
        return(value+1);
    }

    void f()
    {
        int x[function(10)];


    }
};

Более «сумасшедший» образец.

class test3
{
    public:

    int value;

    // constexpr const method - can't chanage the values of object fields and can be evaluated at compile time.
    constexpr int getvalue() const
    {
        return(value);
    }

    constexpr test3(int Value)
        : value(Value)
    {
    }
};


constexpr test3 x(100); // OK. Constructor is constexpr.

int array[x.getvalue()]; // OK. x.getvalue() is constexpr and can be evaluated at compile time.
Timmy_A
источник
Кроме того, в C, constexpr intсуществует, но это пишетсяconst int
curiousguy
8

Как уже указывалось @ 0x499602d2, constтолько гарантирует, что значение не может быть изменено после инициализации, поскольку as constexpr(введено в C ++ 11) гарантирует, что переменная является постоянной времени компиляции.
Рассмотрим следующий пример (из LearnCpp.com):

cout << "Enter your age: ";
int age;
cin >> age;

const int myAge{age};        // works
constexpr int someAge{age};  // error: age can only be resolved at runtime
Локеш Мехер
источник
5

Значение A const int varможно динамически установить в значение во время выполнения, и как только оно будет установлено в это значение, его уже нельзя будет изменить.

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

Вот хороший пример:

int main(int argc, char*argv[]) {
    const int p = argc; 
    // p = 69; // cannot change p because it is a const
    // constexpr int q = argc; // cannot be, bcoz argc cannot be computed at compile time 
    constexpr int r = 2^3; // this works!
    // r = 42; // same as const too, it cannot be changed
}

Приведенный выше фрагмент прекрасно компилируется, и я прокомментировал те, которые приводят к ошибке.

Ключевые понятия, на которые следует обратить внимание, это понятия compile timeи run time. В C ++ были введены новые нововведения, предназначенные для максимально возможного количества ** know **определенных вещей во время компиляции для улучшения производительности во время выполнения.

truthadjustr
источник
3

Я не думаю, что какой-либо из ответов действительно прояснит, какие именно побочные эффекты у него есть, или действительно, что это такое.

constexprи constв namespace / file-scope идентичны, когда инициализируются литералом или выражением; но с функцией, constможет быть инициализирован любой функцией, но constexprинициализирован non-constexpr (функция, которая не помечена как constexpr или выражение не constexpr), будет генерировать ошибку компилятора. И то constexprи другое constнеявно является внутренней связью для переменных (ну, на самом деле, они не доживут до стадии связывания, если компилируют -O1 и более сильные, и staticне заставляют компилятор испускать внутренний (локальный) символ компоновщика для constили constexprкогда в -O1 или более сильный, единственный раз, когда это происходит, если вы берете адрес переменной. constИ constexprбудет внутренним символом, если не выражено с помощью externieextern constexpr/const int i = 3;должен быть использован). В функции constexprделает функцию постоянно никогда не достигающей стадии связывания (независимо от externили inlineв определении или -O0 или -Ofast), тогда как constникогда не достигает, staticи inlineтолько влияет на -O1 и выше. Когда const/ constexprпеременная инициализируется constexprфункцией, загрузка всегда оптимизируется с любым флагом оптимизации, но она никогда не оптимизируется, если функция только staticили inline, или если переменная не является const/ constexpr.

Стандартная компиляция (-O0)

#include<iostream>
constexpr int multiply (int x, int y)
{

  return x * y;
}

extern const int val = multiply(10,10);
int main () {
  std::cout << val;
} 

компилируется в

val:
        .long   100  //extra external definition supplied due to extern

main:
        push    rbp
        mov     rbp, rsp
        mov     esi, 100 //substituted in as an immediate
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        pop     rbp
        ret

__static_initialization_and_destruction_0(int, int):
        . 
        . 
        . 

Однако

#include<iostream>
const int multiply (int x, int y)
{

  return x * y;
}

const int val = multiply(10,10); //constexpr is an error
int main () {
  std::cout << val;
}

Компилируется в

multiply(int, int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     DWORD PTR [rbp-8], esi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, DWORD PTR [rbp-8]
        pop     rbp
        ret

main:
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR val[rip]
        mov     esi, eax
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
        mov     eax, 0
        pop     rbp
        ret

__static_initialization_and_destruction_0(int, int):
        . 
        . 
        . 
        mov     esi, 10
        mov     edi, 10
        call    multiply(int, int)
        mov     DWORD PTR val[rip], eax

Это ясно показывает, что constexprинициализация const/constexprпеременной file-scope происходит во время компиляции и не генерирует глобальный символ, тогда как ее использование не вызывает инициализацию раньше mainво время выполнения.

Компиляция с использованием -Ofast

Даже -Ofast не оптимизирует нагрузку! https://godbolt.org/z/r-mhif , так что вам нужно constexpr


constexprФункции также могут быть вызваны из других constexprфункций для того же результата. constexprфункция также предотвращает использование чего-либо, что не может быть сделано во время компиляции в функции; например, звонок <<оператору на std::cout.

constexprв области видимости блока ведет себя так же, что выдает ошибку, если инициализируется функцией non-constexpr; значение также подставляется сразу.

В конце концов, его основное предназначение похоже на встроенную функцию C, но она эффективна только тогда, когда функция используется для инициализации переменных области файла (что функции не могут делать на C, но они могут на C ++, потому что она позволяет динамическую инициализацию file- переменные области видимости), за исключением того, что функция не может экспортировать глобальный / локальный символ также в компоновщик, даже используя extern/static, что вы могли бы использовать inlineна C; Функции назначения переменных в области блока могут быть встроены просто с помощью оптимизации -O1 без использования constexprC и C ++.

Льюис Келси
источник
Хорошая точка на компоновщик. Можно ли в целом считать более безопасным использование constexpr, поскольку это приводит к уменьшению утечек символов?
Нил МакГилл
1
@NeilMcGill на самом деле не потому, что inline и static заставят компилятор не выдавать локальный символ для умножения, если компилируется с использованием -O1 или более сильной. Constexpr является единственным, который оптимизирует нагрузку для val, но в остальном он идентичен положению static или inline перед функцией. Я забыл еще кое-что. Constexpr - единственное ключевое слово, которое не генерирует символ для функции на -O0, статической и встроенной функции
Льюис Келси
1

Прежде всего, оба являются классификаторами в C ++. Объявленная переменная const должна быть инициализирована и не может быть изменена в будущем. Следовательно, обычно переменная, объявленная как const, будет иметь значение даже до компиляции.

Но для constexpr это немного другое.

Для constexpr вы можете указать выражение, которое можно было бы оценить во время компиляции программы.

Очевидно, что переменная, объявленная как constexper, не может быть изменена в будущем так же, как const.

Субхаш Малередди
источник