constexpr
和 const
有什么区别?
- 我什么时候可以只使用其中之一?
- 我什么时候可以同时使用,我应该如何选择一个?
原文由 MBZ 发布,翻译遵循 CC BY-SA 4.0 许可协议
在 C++ 中,如果一个 const 对象是用一个常量表达式初始化的,那么我们可以在需要常量表达式的任何地方使用我们的 const 对象。
const int x = 10;
int a[x] = {0};
例如,我们可以在 switch 中做一个 case 语句。
constexpr 可以与数组一起使用。
constexpr 不是类型。
constexpr 关键字可以与 auto 关键字一起使用。
constexpr auto x = 10;
struct Data { // We can make a bit field element of struct.
int a:x;
};
如果我们用一个常量表达式初始化一个 const 对象,那么这个 const 对象生成的表达式现在也是一个常量表达式。
常量表达式: 可以在编译时计算其值的表达式。
x*5-4 // 这是一个常量表达式。 对于编译器来说,输入这个表达式和直接输入 46 没有区别。
初始化是强制性的。它只能用于阅读目的。它不能改变。到目前为止,“const”和“constexpr”关键字之间没有区别。
注意: 我们可以在同一个声明中使用 constexpr 和 const。
constexpr const int* p;
通常,函数的返回值是在运行时获得的。 但是当满足某些条件时,对 constexpr 函数的调用将在编译时作为常量获得。
注意: 在函数调用中将参数发送到函数的参数变量,如果有多个参数,则发送到所有参数变量,如果 CE 函数的返回值将在编译时计算。 !!!
constexpr int square (int a){
return a*a;
}
constexpr int a = 3;
constexpr int b = 5;
int arr[square(a*b+20)] = {0}; //This expression is equal to int arr[35] = {0};
为了使函数成为 constexpr 函数,函数的返回值类型和函数参数的类型必须属于称为“文字类型”的类型类别。
constexpr 函数是隐式内联函数。
不需要使用常量表达式调用任何 constexpr 函数。这不是强制性的。如果发生这种情况,计算将不会在编译时完成。它将被视为正常的函数调用。因此,在需要常量表达式的地方,我们将无法再使用该表达式。
1) 函数的参数中使用的类型和函数返回值的类型必须是字面量类型。
2) 不应在函数内部使用具有静态生命周期的局部变量。
3) 如果函数是合法的,当我们在编译时用常量表达式调用这个函数时,编译器会在编译时计算函数的返回值。
4 ) 编译器需要查看函数的代码,所以 constexpr 函数几乎总是在头文件中。
5 ) 为了让我们创建的函数成为 constexpr 函数,函数的定义必须在头文件中。因此,无论哪个源文件包含该头文件,都会看到函数定义。
通常使用默认成员初始化,可以在类中初始化具有 const 和整数类型的静态数据成员。但是,为了做到这一点,必须同时存在“const”和“integral types”。
如果我们使用 static constexpr 那么它不必是一个整数类型来在类中初始化它。只要我用常量表达式初始化它,就没有问题。
class Myclass {
const static int sx = 15; // OK
constexpr static int sy = 15; // OK
const static double sd = 1.5; // ERROR
constexpr static double sd = 1.5; // OK
};
原文由 east1000 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
基本含义和语法
这两个关键字都可以在对象和函数的声明中使用。应用于 对象 时的基本区别是:
const
将对象声明为 _常量_。这意味着保证一旦初始化,该对象的值就不会改变,并且编译器可以利用这一事实进行优化。它还有助于防止程序员编写修改初始化后不打算修改的对象的代码。constexpr
声明一个对象适合在标准中称为 常量表达式 的地方使用。但请注意,constexpr
并不是唯一的方法。当应用于 函数 时,基本区别是:
const
只能用于非静态成员函数,不能用于一般函数。它保证成员函数不会修改任何非静态数据成员(可变数据成员除外,无论如何都可以修改)。constexpr
可以与成员函数和非成员函数以及构造函数一起使用。它声明函数适合在 常量表达式 中使用。编译器只会在函数满足特定标准 (7.1.5⁄3,4) 时接受它,最重要的是(†) :return
语句。在构造函数的情况下,只允许使用初始化列表、typedef 和静态断言。 (= default
和= delete
也是允许的。)asm
声明,goto
语句,带有标签以外的语句case
和default
,try-block,非字面类型变量的定义,静态或线程存储时长的变量的定义,不初始化的变量的定义被执行。常量表达式
如上所述,
constexpr
声明对象和函数都适合在常量表达式中使用。常量表达式不仅仅是常量:但请注意:
将某事声明为
constexpr
并不一定保证它将在编译时进行评估。它 可以用于 此类,但也可以用于在运行时评估的其他地方。一个对象 可能 适合在常量表达式中使用, 而无需 声明
constexpr
。例子:这是可能的,因为
N
是常量并在声明时用文字初始化,满足常量表达式的标准,即使它没有声明constexpr
。那么我什么时候必须使用
constexpr
?N
这样的 对象 可以用作常量表达式 而无需 声明constexpr
。这适用于所有对象:const
[这是由于第 5.19⁄2 节:常量表达式不得包含涉及“左值到右值修改,除非 […] 整数或枚举类型的左值 […]”的子表达式,感谢 Richard Smith 纠正我的早先声称这适用于所有文字类型。]
constexpr
;仅仅满足常量表达式函数的标准是不够的。例子:我什么时候可以/应该同时使用
const
和constexpr
?A. 在对象声明中。 当两个关键字都引用要声明的同一个对象时,这从来没有必要。
constexpr
意味着const
。是相同的
但是,请注意,在某些情况下,每个关键字都引用声明的不同部分:
在这里,
NP
被声明为地址常量表达式,即本身就是常量表达式的指针。 (通过将地址运算符应用于静态/全局常量表达式来生成地址时,这是可能的。)这里,需要constexpr
和const
:constexpr
总是指被声明的表达式(这里是NP
),而const
是指int
(它声明了一个指向常量的指针)。删除const
会使表达式非法(因为 (a) 指向非常量对象的指针不能是常量表达式,并且 (b)&N
实际上是指针- 到常数)。B. 在成员函数声明中。 在 C++11 中,
constexpr
意味着const
,而在 C++14 和 C++17 中则不是这样。在 C++11 下声明为的成员函数需要声明为
在 C++14 下仍然可以用作
const
函数。