C++ `constexpr` 和 `const` 之间的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14116003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between `constexpr` and `const`
提问by MBZ
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?
- 我什么时候可以只使用其中之一?
- 我什么时候可以同时使用,我应该如何选择一个?
采纳答案by jogojapan
Basic meaning and syntax
基本含义和语法
Both keywords can be used in the declaration of objects as well as functions. The basic difference when applied to objectsis this:
这两个关键字都可以在对象和函数的声明中使用。应用于对象时的基本区别是:
const
declares an object as constant. 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. But note thatconstexpr
is not the only way to do this.
const
将对象声明为常量。这意味着保证一旦初始化,该对象的值就不会改变,并且编译器可以利用这一事实进行优化。它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。constexpr
声明一个对象适合用于标准所称的常量表达式。但请注意,这constexpr
不是执行此操作的唯一方法。
When applied to functionsthe basic difference is this:
当应用于函数时,基本的区别是:
const
can only be used for non-static member functions, not functions in general. 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. 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 (†):- The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single
return
statement is allowed. In the case of a constructor, only an initialization list, typedefs and static assert are allowed. (= default
and= delete
are allowed, too, though.) - As of C++14 the rules are more relaxed, what is allowed since then inside a constexpr function:
asm
declaration, agoto
statement, a statement with a label other thancase
anddefault
, 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. - The arguments and the return type must be literal types(i.e., generally speaking, very simple types, typically scalars or aggregates)
- The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single
const
只能用于非静态成员函数,不能用于一般函数。它保证成员函数不会修改任何非静态数据成员。constexpr
可以与成员和非成员函数以及构造函数一起使用。它声明了适合在常量表达式中使用的函数。编译器仅在函数满足特定条件 (7.1.5/3,4) 时才会接受它,最重要的是(†):- 函数体必须是非虚拟的并且非常简单:除了 typedef 和静态断言之外,只
return
允许使用单个语句。在构造函数的情况下,只允许初始化列表、typedef 和静态断言。(= default
和= delete
也被允许使用,但。) - 从 C++14 开始,规则更加宽松,从那时起在 constexpr 函数中允许的内容:
asm
声明,goto
语句,带有除case
and之外的标签的语句default
,try-block,非文字类型变量的定义,静态或线程存储持续时间的变量的定义,未执行初始化的变量的定义。 - 参数和返回类型必须是文字类型(即,一般来说,非常简单的类型,通常是标量或聚合)
- 函数体必须是非虚拟的并且非常简单:除了 typedef 和静态断言之外,只
Constant expressions
常量表达式
As said above, constexpr
declares both objects as well as functions as fit for use in constant expressions. A constant expression is more than merely constant:
如上所述,constexpr
声明适合在常量表达式中使用的对象和函数。常量表达式不仅仅是常量:
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. It can be usedfor such, but it can be used in other places that are evaluated at run-time, as well.An object maybe fit for use in constant expressions withoutbeing declared
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 declaredconstexpr
.
它可以用在需要编译时评估的地方,例如模板参数和数组大小说明符:
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
。
So when do I actually have to use constexpr
?
那么我constexpr
什么时候真正必须使用?
An objectlike
N
above can be used as constant expression withoutbeing declaredconstexpr
. 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.]
For a functionto be fit for use in constant expressions, it mustbe explicitly declared
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 }
像上面这样的对象
N
可以用作常量表达式而无需声明constexpr
。这适用于所有对象:const
- 整数或枚举类型和
- 在声明时用本身是常量表达式的表达式初始化
[这是由于 §5.19/2:常量表达式不得包含涉及“左值到右值修改的子表达式,除非 [...] 整数或枚举类型的泛左值 [...]” 感谢 Richard Smith 更正我的早先声称这适用于所有文字类型。]
对于适合在常量表达式中使用的函数,必须显式声明它
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 }
When can I / should I use both, const
and constexpr
together?
我什么时候可以/我应该同时使用,const
并constexpr
在一起呢?
A. In object declarations.This is never necessary when both keywords refer to the same object to be declared. constexpr
implies const
.
A. 在对象声明中。当两个关键字都指向要声明的同一个对象时,这是不必要的。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, i.e. an pointer that is itself a constant expression. (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). 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).
在这里,NP
被声明为地址常量表达式,即一个指针,它本身就是一个常量表达式。(当通过将地址运算符应用于静态/全局常量表达式来生成地址时,这是可能的。)在这里,constexpr
和const
都是必需的:constexpr
始终指代声明的表达式(此处NP
),而const
指代int
(它声明了一个指针-到常量)。删除const
会使表达式非法(因为 (a) 指向非常量对象的指针不能是常量表达式,而 (b)&N
实际上是指向常量的指针)。
B. In member function declarations.In C++11, constexpr
implies const
, while in C++14 and C++17 that is not the case. A member function declared under C++11 as
B. 在成员函数声明中。在 C++11 中,constexpr
蕴涵const
,而在 C++14 和 C++17 中,情况并非如此。在 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.
在 C++14 下,以便仍可用作const
函数。
回答by Karthik T
const
applies for variables, and prevents them from being modifiedin your code.
const
适用于variables,并防止它们在您的代码中被修改。
constexpr
tells the compiler that this expressionresults in a compile time constant value, so it can be used in places like array lengths, assigning to const
variables, etc. The linkgiven by Oli has a lot of excellent examples.
constexpr
告诉编译器这个表达式的结果是一个编译时常量 value,所以它可以用在数组长度、赋值给const
变量等地方。Oli 给出的链接有很多很好的例子。
Basically they are 2 different concepts altogether, and can (and should) be used together.
基本上它们是两个不同的概念,可以(并且应该)一起使用。
回答by zangw
Overview
概述
const
guarantees that a program does not change an object's value. However,const
does not guarantee which type of initialization the object undergoes.Consider:
const int mx = numeric_limits<int>::max(); // OK: runtime initialization
The function
max()
merely returns a literal value. However, because the initializer is a function call,mx
undergoes runtime initialization. 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. 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 expressionsthat are crucial for time-critical applications, system programming, templates, and generally speaking, in any code that relies on compile-time constants.
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
您可以定义真正的常量表达式,这些表达式对于时间关键型应用程序、系统编程、模板以及一般而言,在依赖编译时常量的任何代码中都是至关重要的。
Constant-expression functions
常量表达式函数
A constant-expression functionis a function declared constexpr
. Its body must be non-virtual and consist of a single return statement only, apart from typedefs and static asserts. 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.
甲常数表达式函数是声明的函数constexpr
。除了 typedef 和静态断言之外,它的主体必须是非虚拟的,并且仅由单个 return 语句组成。它的参数和返回值必须具有文字类型。它可以与非常量表达式参数一起使用,但是当这样做时,结果不是一个常量表达式。
A constant-expression function is meant to replace macrosand hardcoded literalswithout 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 objectis an object declared constexpr
. It must be initialized with a constant expression or an rvalue constructed by a constant-expression constructor with constant-expression arguments.
甲常数表达式对象是声明的目的constexpr
。它必须使用常量表达式或由具有常量表达式参数的常量表达式构造函数构造的右值进行初始化。
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. Consequently, a constant-expression object can always be used as part of another constant expression.
一个常量表达式对象的行为就像它被声明一样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
Constant-expression constructors
常量表达式构造函数
A constant-expression constructoris a constructor declared constexpr
. It can have a member initialization list but its body must be empty, apart from typedefs and static asserts. Its arguments must have literal types.
甲常数表达式构造是声明的构造constexpr
。它可以有一个成员初始化列表,但它的主体必须是空的,除了 typedef 和静态断言。它的参数必须具有文字类型。
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所著《Effective Modern C++》一书中的提示constexpr
:
constexpr
objects are const and are initialized with values known during compilation;constexpr
functions produce compile-time results when called with arguments whose values are known during compilation;constexpr
objects and functions may be used in a wider range of contexts than non-constexpr
objects and functions;constexpr
is part of an object's or function's interface.
constexpr
对象是常量,并使用编译期间已知的值进行初始化;constexpr
函数在使用编译期间已知值的参数调用时产生编译时结果;constexpr
对象和函数可以在比非constexpr
对象和函数更广泛的上下文中使用;constexpr
是对象或函数接口的一部分。
Source: Using constexpr to Improve Security, Performance and Encapsulation in C++.
回答by Mustafa Ekici
According to book of "The C++ Programming Language 4th Editon" by Bjarne Stroustrup
? const: meaning roughly ‘‘I promise not to change this value'' (§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.
? constexpr: meaning roughly ‘‘to be evaluated at compile time'' (§10.4). This is used primarily to specify constants, to allow
For example:
根据 Bjarne Stroustrup 的“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.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.
For example:
要使函数可在常量表达式中使用,即在将由编译器计算的表达式中,它必须定义为constexpr。
例如:
constexpr double square(double x) { return x?x; }
To be constexpr, a function must be rather simple: just a return-statement computing a value. A
constexpr function can be used for non-constant arguments, but when that is done the result is not a
constant expression. 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.
In a few places, constant expressions are required by language rules (e.g., 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). 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).
要成为 constexpr,函数必须相当简单:只是一个计算值的返回语句。constexpr 函数可用于非常量参数,但完成后结果不是常量表达式。我们允许在不需要常量表达式的上下文中使用非常量表达式参数调用 constexpr 函数,因此我们不必两次定义本质上相同的函数:一次用于常量表达式,一次用于变量。
在一些地方,语言规则需要常量表达式(例如,数组边界(第 2.2.5 节、第 7.3 节)、案例标签(第 2.2.4 节、第 9.4.2 节)、一些模板参数(第 25.2 节)和使用 constexpr 声明的常量)。在其他情况下,编译时评估对性能很重要。独立于性能问题,不变性(具有不可更改状态的对象)的概念是一个重要的设计问题(第 10.4 节)。
回答by Timmy_A
Both const
and constexpr
can be applied to variables and functions. Even though they are similar to each other, in fact they are very different concepts.
二者const
并constexpr
可以应用到变量和函数。尽管它们彼此相似,但实际上它们是非常不同的概念。
Both const
and constexpr
mean that their values can't be changed after their initialization. So for example:
双方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.
The principal difference between const
and constexpr
is the time when their initialization values are known (evaluated). While the values of const
variables can be evaluated at both compile time and runtime, constexpr
are always evaluated at compile time. For example:
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.
The key advantage to know if the value is known at compile time or runtime is the fact that compile time constants can be used whenever compile time constants are needed. For instance, C++ doesn't allow you to specify C-arrays with the variable lengths.
知道该值在编译时还是运行时已知的关键优势在于,只要需要编译时常量,就可以使用编译时常量。例如,C++ 不允许您指定具有可变长度的 C 数组。
int temp=rand(); // temp is generated by the the random generator at runtime.
int array1[10]; // OK.
int array2[temp]; // ERROR.
So it means that:
所以这意味着:
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.
So const
variables can define both compile time constantslike size1
that can be used to specify array sizes and runtime constantslike size2
that are known only at runtime and can't be used to define array sizes. On the other hand constexpr
always define compile time constants that can specify array sizes.
这样const
的变量可以定义两个编译时间常数等size1
,可被用来指定数组的大小和运行时间常数等size2
,只有在运行时是已知的,并且不能被用来定义阵列的尺寸。另一方面,constexpr
始终定义可以指定数组大小的编译时常量。
Both const
and constexpr
can be applied to functions too. A const
function must be a member function (method, operator) where application of const
keyword means that the method can't change the values of their member (non-static) fields. For example.
双方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.
}
};
A constexpr
is a different concept. It marks a function (member or non-member) as the function that can be evaluated at compile time if compile time constants are passed as their arguments. For example you can write this.
Aconstexpr
是一个不同的概念。如果编译时常量作为参数传递,它将函数(成员或非成员)标记为可以在编译时评估的函数。例如你可以写这个。
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.
By the way the constexpr
functions are the regular C++ functions that can be called even if non-constant arguments are passed. But in that case you are getting the non-constexpr values.
顺便说一下,这些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.
The constexpr
can be also applied to the member functions (methods), operators and even constructors. For instance.
的constexpr
也可应用于所述成员函数(方法),操作者和甚至构造函数。例如。
class test2
{
static constexpr int function(int value)
{
return(value+1);
}
void f()
{
int x[function(10)];
}
};
A more 'crazy' sample.
一个更“疯狂”的样本。
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.
回答by Lokesh Meher
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.
Consider the following example(from LearnCpp.com):
正如@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
回答by typelogic
A const int var
can be dynamically set to a value at runtime and once it is set to that value, it can no longer be changed.
Aconst int var
可以在运行时动态设置为一个值,一旦设置为该值,就不能再更改。
A constexpr int var
cannot be dynamically set at runtime, but rather, at compile time. And once it is set to that value, it can no longer be changed.
Aconstexpr int var
不能在运行时动态设置,而是在编译时动态设置。一旦设置为该值,就无法再更改。
Here is a solid example:
这是一个可靠的例子:
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
}
The snippet above compiles fine and I have commented out those that cause it to error.
上面的代码片段编译得很好,我已经注释掉了那些导致它出错的代码。
The key notions here to take note of, are the notions of compile time
and run time
. New innovations have been introduced into C++ intended to as much as possible ** know **
certain things at compilation time to improve performance at runtime.
这里的关键概念要注意的,是的概念compile time
和run time
。C++ 中引入了新的创新,旨在尽可能多地** know **
在编译时提高运行时的性能。
回答by Lewis Kelsey
I don't think any of the answers really make it clear exactly what side effects it has, or indeed, what it is.
我认为任何答案都没有真正说明它有什么副作用,或者确实是什么。
constexpr
and const
at namespace/file-scope are identical when initialised with a literal or expression; but with a function, const
can be initialised by any function, but constexpr
initialised by a non-constexpr function will generate a compiler error. Both constexpr
and const
are implicitly internal linkage for variables (well actually, they don't survive to get to the linking stage if compiling -O1 and stronger, and static
doesn't force the compiler to emit an internal (local) linker symbol for const
or constexpr
when at -O1 or stronger; the only time it does this is if you take the address of the variable. const
and constexpr
will be an internal symbol unless expressed with extern
i.e. extern constexpr/const int i = 3;
needs to be used). On a function, constexpr
makes the function permanently never reach the linking stage (regardless of extern
or inline
in the definition or -O0 or -Ofast), whereas const
never does, and static
and inline
only have this effect on -O1 and above. When a const
/constexpr
variable is initialised by a constexpr
function, the load is always optimised out with any optimisation flag, but it is never optimised out if the function is only static
or inline
, or if the variable is not a const
/constexpr
.
constexpr
和const
在名字空间/文件范围时用文字或表达初始化是相同的; 但是对于一个函数,const
可以由任何函数constexpr
初始化,但由非 constexpr 函数初始化将产生编译器错误。这两个constexpr
和const
是变量隐含内部链接(当然实际上,他们根本无法生存,如果编译-O1做强才能到连接阶段,并static
没有强制编译器发出内部(本地)连接符号const
或constexpr
在当-O1或更强;它这样做的唯一的时间是,如果你把变量的地址。const
和constexpr
将是一个内部符号除非表示与extern
即extern constexpr/const int i = 3;
需要使用)。在一个函数上,constexpr
使功能永久不会到达连接阶段(无论extern
或inline
在定义或-O0或-Ofast),而const
从来不,并且static
和inline
只对-O1和上述这种效果。当一个const
/constexpr
变量被一个constexpr
函数初始化时,加载总是用任何优化标志优化出来,但如果函数只是static
或inline
,或者如果变量不是const
/ ,它永远不会优化出来constexpr
。
Standard compilation (-O0)
标准编译 (-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;
}
compiles to
编译为
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):
.
.
.
However
然而
#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;
}
Compiles to
编译为
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
This clearly shows that constexpr
causes the initialisation of the const/constexpr
file-scope variable to occur at compile time and produce no global symbol, whereas not using it causes initialisation to occur before main
at runtime.
这清楚地表明这constexpr
会导致const/constexpr
文件范围变量的初始化在编译时发生并且不产生全局符号,而不使用它会导致main
在运行时之前发生初始化。
Compiling using -Ofast
使用 -Ofast 编译
Even -Ofast doesn't optimise out the load! https://godbolt.org/z/r-mhif, so you needconstexpr
即使 -Ofast 也不会优化负载!https://godbolt.org/z/r-mhif,所以你需要constexpr
constexpr
functions can also be called from inside other constexpr
functions for the same result. constexpr
on a function also prevents use of anything that can't be done at compile time in the function; for instance, a call to the <<
operator on std::cout
.
constexpr
函数也可以从其他constexpr
函数内部调用以获得相同的结果。constexpr
在函数上还可以防止在函数中使用在编译时无法完成的任何事情;例如,在 上呼叫<<
操作员std::cout
。
constexpr
at block scope behaves the same in that it produces an error if initialised by a non-constexpr function; the value is also substituted in immediately.
constexpr
at 块作用域的行为相同,如果由非 constexpr 函数初始化,则会产生错误;该值也立即被替换。
In the end, its main purpose is like C's inline function, but it is only effective when the function is used to initialise file-scope variables (which functions cannot do on C, but they can on C++ because it allows dynamic initialisation of file-scope variables), except the function cannot export a global/local symbol to the linker as well, even using extern/static
, which you could with inline
on C; block-scope variable assignment functions can be inlined simply using an -O1 optimisation without constexpr
on C and C++.
最后,它的主要目的就像 C 的内联函数一样,但只有在该函数用于初始化文件范围变量时才有效(这些函数在 C 上不能做,但在 C++ 上可以,因为它允许动态初始化文件-范围变量),除了该函数也不能将全局/局部符号导出到链接器,即使使用extern/static
,您也可以inline
在 C 上使用;块范围变量赋值函数可以简单地使用 -O1 优化来内联,而不需要constexpr
在 C 和 C++ 上。
回答by Subhash Malireddy
First of all, both are qualifiers in c++. A variable declared const must be initialized and cannot be changed in the future. Hence generally a variable declared as a const will have a value even before compiling.
首先,两者都是 C++ 中的限定符。声明为 const 的变量必须被初始化并且以后不能更改。因此,通常声明为 const 的变量甚至在编译之前就有一个值。
But, for constexpr it is a bit different.
但是,对于 constexpr,它有点不同。
For constexpr, you can give an expression that could be evaluated during the compilation of the program.
对于 constexpr,您可以给出一个可以在程序编译期间计算的表达式。
Obviously, the variable declared as constexper cannot be changed in the future just like const.
显然,声明为 constexper 的变量在以后不能像 const 一样改变。