天天看點

constexpr和const之間的差別

本文翻譯自:Difference between `constexpr` and `const`

What's the difference between

constexpr

and

const

?

constexpr

const

什麼差別?
  • When can I use only one of them? 什麼時候隻能使用其中之一?
  • When can I use both and how should I choose one? 什麼時候可以同時使用兩者?應該如何選擇?

#1樓

參考:https://stackoom.com/question/xEDT/constexpr和const之間的差別

#2樓

const

applies for variables , and prevents them from being modified in your code.

const

适用于變量 ,并防止它們在您的代碼中被修改 。

constexpr

tells the compiler that this expression results in a compile time constant value , so it can be used in places like array lengths, assigning to

const

variables, etc. The link given by Oli has a lot of excellent examples.

constexpr

告訴編譯器該表達式産生一個編譯時間常數值 ,是以可以在諸如數組長度,配置設定給

const

變量等地方使用。Oli提供的連結有很多很好的例子。

Basically they are 2 different concepts altogether, and can (and should) be used together.

基本上,它們總共是2個不同的概念,可以(并且應該)一起使用。

#3樓

Basic meaning and syntax 基本含義和文法

Both keywords can be used in the declaration of objects as well as functions.

這兩個關鍵字都可以在對象和函數的聲明中使用。

The basic difference when applied to objects is this:

應用于對象的基本差別是:
  • const

    declares an object as constant .

    const

    聲明一個對象為常量 。
    This implies a guarantee that, once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. 這意味着保證,一旦初始化,該對象的值就不會改變,并且編譯器可以利用這一事實進行優化。 It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization. 它還有助于防止程式員編寫代碼來修改在初始化後不希望修改的對象。
  • constexpr

    declares an object as fit for use in what the Standard calls constant expressions .

    constexpr

    聲明一個對象适合在标準調用的常量表達式中使用 。
    But note that

    constexpr

    is not the only way to do this. 但是請注意,

    constexpr

    并非唯一的方法。

When applied to functions the basic difference is this:

當應用于函數時 ,基本差別是:
  • const

    can only be used for non-static member functions, not functions in general.

    const

    隻能用于非靜态成員函數,而不能用于一般函數。
    It gives a guarantee that the member function does not modify any of the non-static data members. 它保證成員函數不會修改任何非靜态資料成員。
  • constexpr

    can be used with both member and non-member functions, as well as constructors.

    constexpr

    可以與成員函數和非成員函數以及構造函數一起使用。
    It declares the function fit for use in constant expressions . 它聲明該函數适合在常量表達式中使用。 The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly (†) : 僅當函數滿足某些條件(7.1.5 / 3,4),最重要的是(†)時 ,編譯器才會接受它:
    • The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single

      return

      statement is allowed. 函數體必須是非虛拟的,并且必須非常簡單:除了typedef和static斷言,僅允許單個

      return

      語句。
      In the case of a constructor, only an initialization list, typedefs and static assert are allowed. 對于構造函數,僅允許使用初始化清單,typedef和靜态斷言。 (

      = default

      and

      = delete

      are allowed, too, though.) (不過,也允許使用

      = default

      = delete

      。)
    • As of C++14 the rules are more relaxed, what is allowed since then inside a constexpr function:

      asm

      declaration, a

      goto

      statement, a statement with a label other than

      case

      and

      default

      , try-block, definition of a variable of non-literal type, definition of a variable of static or thread storage duration, definition of a variable for which no initialization is performed. 從C ++ 14開始,規則更加寬松,此後允許在constexpr函數中使用:

      asm

      聲明,

      goto

      語句,帶有除

      case

      default

      之外的标簽的語句,try-block,non變量的定義類型類型,靜态或線程存儲持續時間變量的定義,未執行初始化的變量的定義。
    • The arguments and the return type must be literal types (ie, generally speaking, very simple types, typically scalars or aggregates) 參數和傳回類型必須是文字類型 (即,通常來說,非常簡單的類型,通常是标量或集合)

Constant expressions 常數表達式

As said above,

constexpr

declares both objects as well as functions as fit for use in constant expressions.

如上所述,

constexpr

聲明兩個對象以及适合在常量表達式中使用的函數。

A constant expression is more than merely constant:

常量表達式不僅僅是常量:
  • It can be used in places that require compile-time evaluation, for example, template parameters and array-size specifiers: 它可以在需要編譯時評估的地方使用,例如模闆參數和數組大小說明符:
  • But note: 但請注意:
    • Declaring something as

      constexpr

      does not necessarily guarantee that it will be evaluated at compile time. 将某些東西聲明為

      constexpr

      并不一定保證它将在編譯時進行評估。
      It can be used for such, but it can be used in other places that are evaluated at run-time, as well. 它可以用于此目的 ,但也可以在運作時評估的其他地方使用。
    • An object may be fit for use in constant expressions without being declared

      constexpr

      . 一個對象可能适合在常量表達式中使用, 而無需聲明

      constexpr

      Example: 例:
    This is possible because

    N

    , being constant and initialized at declaration time with a literal, satisfies the criteria for a constant expression, even if it isn't declared

    constexpr

    . 這是可能的,因為

    N

    是常量,并且在聲明時使用文字立即初始化,即使未聲明

    constexpr

    ,它也滿足常量表達式的條件。

So when do I actually have to use

constexpr

?

那麼,我什麼時候真正必須使用

constexpr

  • An object like

    N

    above can be used as constant expression without being declared

    constexpr

    . 像上面的

    N

    這樣的對象可以用作常量表達式, 而無需聲明

    constexpr

    This is true for all objects that are: 對于以下所有對象都是如此:
    • const

    • of integral or enumeration type and 整型或枚舉類型的,并且
    • initialized at declaration time with an expression that is itself a constant expression 在聲明時使用本身就是常量表達式的表達式進行初始化
    [This is due to §5.19/2: A constant expression must not include a subexpressions that involves "an lvalue-to-rvalue modification unless […] a glvalue of integral or enumeration type […]" Thanks to Richard Smith for correcting my earlier claim that this was true for all literal types.] [這是由于第5.19 / 2條所緻:常量表達式不得包含涉及“從左值到右值的修改,除非[...]整數或枚舉類型的[...]的glvalue”的子表達式”感謝Richard Smith糾正了早些時候聲稱對所有文字類型都是如此。]
  • For a function to be fit for use in constant expressions, it must be explicitly declared

    constexpr

    ; 為了使函數适合在常量表達式中使用, 必須将其顯式聲明為

    constexpr

    it is not sufficient for it merely to satisfy the criteria for constant-expression functions. 僅滿足常數表達式函數的标準是不夠的。 Example: 例:

When can I / should I use both,

const

and

constexpr

together?

我什麼時候可以同時使用

const

constexpr

A. In object declarations.

A.在對象聲明中。

This is never necessary when both keywords refer to the same object to be declared.

當兩個關鍵字都引用相同的要聲明的對象時,就永遠不需要這樣做。

constexpr

implies

const

.

constexpr

暗示

const

constexpr const int N = 5;
           

is the same as

是相同的
constexpr int N = 5;
           

However, note that there may be situations when the keywords each refer to different parts of the declaration:

但是,請注意,在某些情況下,關鍵字每個都引用聲明的不同部分:
static constexpr int N = 3;

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

Here,

NP

is declared as an address constant-expression, ie an pointer that is itself a constant expression.

此處,

NP

被聲明為位址常量表達式,即本身就是常量表達式的指針。

(This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both

constexpr

and

const

are required:

constexpr

always refers to the expression being declared (here

NP

), while

const

refers to

int

(it declares a pointer-to-const).

(當通過将位址運算符應用于靜态/全局常量表達式來生成位址時,這是可能的。)在這裡,

constexpr

const

都是必需的:

constexpr

始終引用要聲明的表達式(此處為

NP

),而

const

引用

int

(它聲明了一個指向常量的指針)。

Removing the

const

would render the expression illegal (because (a) a pointer to a non-const object cannot be a constant expression, and (b)

&N

is in-fact a pointer-to-constant).

删除

const

将使表達式非法(因為(a)指向非const對象的指針不能是常量表達式,并且(b)

&N

實際上是指向常量的指針)。

B. In member function declarations.

B.在成員函數聲明中。

In C++11,

constexpr

implies

const

, while in C++14 and C++17 that is not the case.

在C ++ 11中,

constexpr

隐含

const

,而在C ++ 14和C ++ 17中則并非如此。

A member function declared under C++11 as

在C ++ 11下聲明為的成員函數為
constexpr void f();
           

needs to be declared as

需要聲明為
constexpr void f() const;
           

under C++14 in order to still be usable as a

const

function.

為了仍然可用作

const

函數,請在C ++ 14下使用。

#4樓

According to book of "The C++ Programming Language 4th Editon" by Bjarne Stroustrup

根據Bjarne Stroustrup撰寫的“ The C ++ Programming Language 4th Editon”一書

• const : meaning roughly ''I promise not to change this value'' (§7.5).

• const :大緻意思是“我保證不會更改此值”(第7.5節)。

This is used primarily to specify interfaces, so that data can be passed to functions without fear of it being modified.

這主要用于指定接口,以便可以将資料傳遞給函數而不必擔心會被修改。

The compiler enforces the promise made by const.

編譯器執行const作出的承諾。

• constexpr : meaning roughly ''to be evaluated at compile time'' (§10.4).

• constexpr :大緻意思是“在編譯時求值”(第10.4節)。

This is used primarily to specify constants, to allow

這主要用于指定常量,以允許

For example:

例如:
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.4∗square(var); // error : var is not a constant expression
const double max3 = 1.4∗square(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
           

For a function to be usable in a constant expression, that is, in an expression that will be evaluated by the compiler, it must be defined constexpr .

為了使函數在常量表達式(即将由編譯器求值的表達式)中使用,必須将其定義為constexpr 。

For example:

例如:
constexpr double square(double x) { return x∗x; }
           

To be constexpr, a function must be rather simple: just a return-statement computing a value.

要成為constexpr,函數必須非常簡單:僅是一個計算值的傳回語句。

A constexpr function can be used for non-constant arguments, but when that is done the result is not a constant expression.

constexpr函數可用于非恒定參數,但這樣做的結果不是恒定表達式。

We allow a constexpr function to be called with non-constant-expression arguments in contexts that do not require constant expressions, so that we don't hav e to define essentially the same function twice: once for constant expressions and once for variables.

我們允許在不需要常量表達式的上下文中使用非常量表達式參數調用constexpr函數,是以我們不必兩次定義本質上相同的函數:一次用于常量表達式,一次用于變量。

In a few places, constant expressions are required by language rules (eg, array bounds (§2.2.5, §7.3), case labels (§2.2.4, §9.4.2), some template arguments (§25.2), and constants declared using constexpr).

在某些地方,語言規則(例如,數組邊界(第2.2.5節,第7.3節),大小寫标簽(第2.2.4節,第9.4.2節),一些模闆參數(第25.2節)和使用constexpr聲明的常量)。

In other cases, compile-time evaluation is important for performance.

在其他情況下,編譯時評估對于性能很重要。

Independently of performance issues, the notion of immutability (of an object with an unchangeable state) is an important design concern (§10.4).

與性能問題無關,(具有不變狀态的對象的)不變性的概念是一個重要的設計問題(第10.4節)。

#5樓

Overview 總覽

  • const

    guarantees that a program does not change an object's value .

    const

    保證程式不會更改對象的value 。
    However,

    const

    does not guarantee which type of initialization the object undergoes. 但是,

    const

    不保證對象将進行哪種類型的初始化。
    Consider: 考慮: The function

    max()

    merely returns a literal value. 函數

    max()

    僅傳回文字值。
    However, because the initializer is a function call,

    mx

    undergoes runtime initialization. 但是,由于初始化程式是函數調用,是以

    mx

    會進行運作時初始化。
    Therefore, you cannot use it as a constant expression : 是以,不能将其用作常量表達式 :
  • constexpr

    is a new C++11 keyword that rids you of the need to create macros and hardcoded literals.

    constexpr

    是一個新的C ++ 11關鍵字,使您無需建立宏和寫死的文字。
    It also guarantees, under certain conditions, that objects undergo static initialization . 它還可以確定在某些條件下對象可以進行靜态初始化 。 It controls the evaluation time of an expression. 它控制表達式的評估時間。 By enforcing compile-time evaluation of its expression ,

    constexpr

    lets you define true constant expressions that are crucial for time-critical applications, system programming, templates, and generally speaking, in any code that relies on compile-time constants. 通過對表達式的編譯時求值 ,

    constexpr

    可以讓您定義真正的常量表達式 ,這些表達式對于依賴于時間的應用程式,系統程式設計,模闆以及通常來說對于依賴編譯時常量的任何代碼都至關重要。

Constant-expression functions 常數表達函數

A constant-expression function is a function declared

constexpr

.

常量表達式函數是聲明為

constexpr

的函數。

Its body must be non-virtual and consist of a single return statement only, apart from typedefs and static asserts.

它的主體必須是非虛拟的,并且除了typedef和static斷言外,隻能由單個return語句組成。

Its arguments and return value must have literal types.

它的參數和傳回值必須具有文字類型。

It can be used with non-constant-expression arguments, but when that is done the result is not a constant expression.

可以将其與非常量表達式參數一起使用,但是完成後的結果将不是常量表達式。

A constant-expression function is meant to replace macros and hardcoded literals without sacrificing performance or type safety.

常量表達式函數旨在替換宏和寫死文字,而不會犧牲性能或類型安全性。
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)
           

Constant-expression objects 常量表達式對象

A constant-expression object is an object declared

constexpr

.

常量表達式對象是聲明為

constexpr

的對象。

It must be initialized with a constant expression or an rvalue constructed by a constant-expression constructor with constant-expression arguments.

它必須使用常量表達式或由帶有常量表達式參數的常量表達式構造函數構造的右值初始化。

A constant-expression object behaves as if it was declared

const

, except that it requires initialization before use and its initializer must be a constant expression.

常量表達式對象的行為就像聲明為

const

,隻是它在使用前需要進行初始化并且其初始化程式必須是常量表達式。

Consequently, a constant-expression object can always be used as part of another constant expression.

是以,常量表達式對象始終可以用作另一個常量表達式的一部分。
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
           

Constant-expression constructors 常量表達式構造函數

A constant-expression constructor is a constructor declared

constexpr

.

常量表達式構造函數是聲明為

constexpr

的構造函數。

It can have a member initialization list but its body must be empty, apart from typedefs and static asserts.

它可以有一個成員初始化清單,但是除了typedef和static斷言之外,它的主體必須為空。

Its arguments must have literal types.

它的參數必須具有文字類型。

A constant-expression constructor allows the compiler to initialize the object at compile-time, provided that the constructor's arguments are all constant expressions.

常量表達式構造函數允許編譯器在編譯時初始化對象,前提是構造函數的參數均為常量表達式。
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
           

Tips from the book Effective Modern C++ by Scott Meyers about

constexpr

:

斯科特·邁耶斯(Scott Meyers)寫的《 有效的現代C ++》中有關

constexpr

  • constexpr

    objects are const and are initialized with values known during compilation;

    constexpr

    對象是const,并使用編譯期間已知的值進行初始化;
  • constexpr

    functions produce compile-time results when called with arguments whose values are known during compilation;

    constexpr

    函數在編譯期間用其值已知的參數調用時會産生編譯時結果。
  • constexpr

    objects and functions may be used in a wider range of contexts than non-

    constexpr

    objects and functions; 與非

    constexpr

    對象和函數相比,

    constexpr

    對象和函數可以在更廣泛的上下文中使用。
  • constexpr

    is part of an object's or function's interface.

    constexpr

    是對象或函數接口的一部分。

Source: Using constexpr to Improve Security, Performance and Encapsulation in C++ .

資料來源: 使用constexpr改善C ++的安全性,性能和封裝 。

#6樓

As @0x499602d2 already pointed out,

const

only ensures that a value cannot be changed after initialization where as

constexpr

(introduced in C++11) guarantees the variable is a compile time constant.

正如@ 0x499602d2已經指出的那樣,

const

僅確定初始化後不能更改值,而

constexpr

(在C ++ 11中引入)保證變量是編譯時間常數。

Consider the following example(from LearnCpp.com):

考慮以下示例(來自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
           

繼續閱讀