问题描述
constexpr
和 const
有什么区别?
- 我什么时候可以只使用其中之一?
- 我什么时候可以同时使用两者,我应该如何选择一个?
推荐答案
基本含义和语法
这两个关键字都可以用于对象和函数的声明.应用于对象时的基本区别是:
const
将对象声明为 constant.这意味着保证一旦初始化,该对象的值就不会改变,并且编译器可以利用这一事实进行优化.它还有助于防止程序员编写修改初始化后不打算修改的对象的代码.
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
声明一个对象适合用于标准所称的常量表达式.但请注意,constexpr
并不是唯一的方法.
constexpr
declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr
is not the only way to do this.
当应用于函数时,基本的区别是:
When applied to functions the basic difference is this:
const
只能用于非静态成员函数,不能用于一般函数.它保证成员函数不会修改任何非静态数据成员(可变数据成员除外,无论如何都可以修改).
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 (except for mutable data members, which can be modified anyway).
constexpr
可以与成员和非成员函数以及构造函数一起使用.它声明了适合在常量表达式中使用的函数.编译器只有在函数满足特定条件(7.1.5/3,4)时才会接受它,最重要的是(†):
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 (†):
- 函数体必须是非虚拟的并且非常简单:除了 typedef 和静态断言,只允许一个
return
语句.对于构造函数,只允许使用初始化列表、typedef 和静态断言.(不过,= default
和= delete
也是允许的.) - 从 C++14 开始,规则更加宽松,从那时起在 constexpr 函数中允许使用:
asm
声明、goto
语句、带有case
和default
以外的标签,try-block,非文字类型变量的定义,静态或线程存储期变量的定义,定义未对其执行初始化的变量. - 参数和返回类型必须是文字类型(即,一般来说,非常简单的类型,通常是标量或聚合)
- 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, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the 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)
如上所述,constexpr
声明了适合在常量表达式中使用的对象和函数.常量表达式不仅仅是常量:
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:
它可以用在需要编译时评估的地方,例如模板参数和数组大小说明符:
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:
将某些内容声明为 constexpr
并不一定保证它会在编译时被评估.它可以用于,但也可以用于其他在运行时进行评估的地方.
Declaring something as constexpr
does not necessarily guarantee that it will be evaluated at compile time. It can be used for such, but it can be used in other places that are evaluated at run-time, as well.
对象可能适用于常量表达式而无需声明constexpr
.示例:
An object may be fit for use in constant expressions without being declared constexpr
. Example:
int main()
{
const int N = 3;
int numbers[N] = {1, 2, 3}; // N is constant expression
}
这是可能的,因为 N
是常量并在声明时用文字初始化,满足常量表达式的标准,即使它没有声明 constexpr
.
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
.
那么我什么时候真正需要使用constexpr
?
- 像上面的
N
这样的对象可以用作常量表达式而无需声明constexpr
.这适用于以下所有对象: const
- 整数或枚举类型和
- 在声明时用一个本身是常量表达式的表达式初始化
- An object like
N
above can be used as constant expression without being 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
[这是由于 §5.19/2:常量表达式不得包含涉及左值到右值修改的子表达式,除非 [...] 整数或枚举类型的泛左值 [...]";感谢 Richard Smith 纠正了我之前的说法,即这适用于所有文字类型.]
要使函数适合在常量表达式中使用,它必须显式声明
constexpr
;仅仅满足常量表达式函数的标准是不够的.示例:
For a function to be fit for use in constant expressions, it must be 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
}
我什么时候可以/应该同时使用 const
和 constexpr
一起使用?
When can I / should I use both, const
and constexpr
together?
A.在对象声明中. 当两个关键字都指向要声明的同一个对象时,这是不必要的.constexpr
意味着 const
.
A. In object declarations. This is never necessary when both keywords refer to the same object to be declared. constexpr
implies const
.
constexpr const int N = 5;
与
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;
}
这里,NP
被声明为一个地址常量表达式,即一个本身就是一个常量表达式的指针.(当通过将地址运算符应用于静态/全局常量表达式来生成地址时,这是可能的.)这里,constexpr
和 const
都是必需的:constexpr
总是指被声明的表达式(这里是 NP
),而 const
指的是 int
(它声明了一个指向-常量).删除 const
会使表达式非法(因为 (a) 指向非常量对象的指针不能是常量表达式,并且 (b) &N
在-事实上是一个指向常量的指针).
Here, NP
is declared as an address constant-expression, i.e. a 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).
B.在成员函数声明中. 在 C++11 中,constexpr
意味着 const
,而在 C++14 和 C++17 中则不然.在C++11下声明为
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
constexpr void f();
需要声明为
constexpr void f() const;
在 C++14 下,以便仍可用作 const
函数.
under C++14 in order to still be usable as a const
function.
这篇关于`constexpr` 和 `const` 之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!