constexpr和const之間的區別

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

What's the difference between constexpr and const ? constexprconst什麼區別?

  • 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語句,帶有除casedefault之外的標籤的語句,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: 它可以在需要編譯時評估的地方使用,例如模板參數和數組大小說明符:

     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 
  • 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: 例:

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

    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: 例:

     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 } 

When can I / should I use both, const and constexpr together? 我什麼時候可以同時使用constconstexpr

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). (當通過將地址運算符應用於靜態/全局常量表達式來生成地址時,這是可能的。)在這裏, constexprconst都是必需的: 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: 考慮:

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

    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 : 因此,不能將其用作常量表達式

     int arr[mx]; // error: “constant expression required” 
  • 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章