const
和constexpr
constexpr
常量表达式:是指值不会改变且在编译期间就可以计算处结果的表达式
常量表达式是由
- 数据类型
- 数据初始值
决定的。
int a = 1
a 不是一个常量表达式,因为它的数据类型不是常量
const int b = get_val()
b不是一个常量表达式,因为它的初始值不是常量
由于使用const
不能确定一个表达式是不是常量,因此C++11使用constexpr
修饰符,可以让编译器在编译期间检查一个表达式是不是常量。
下面这个程序是不正确的,因为a虽然被const
修饰,但它并不是常量表达式,它引用了非常量表达式,因此在编译期间就可以确定它不是常量表达式
1 | int main(void) |
而只要将a = b
改为 a = 1
程序就不会报错了,因为此时a的确是一个常量表达式
constexpr
函数
普通的函数不是常量表达式,但我们可以定义constexpr
类型的函数,它可以作为常量表达式,但这个函数必须简单到可以在编译期间被确定
constexpr
指针 & 引用
constexpr
指向的位置必须是全局变量,静态变量,或者字面值等放在.bss
节.data
位置的数据,而不能是放在栈上的本地变量,因为他们必须在运行时才能确定位置,而不能在编译时确定位置。
const
const
用来修饰变量,根据const
出现的位置,可以分为两种const
:顶层const
和底层const
顶层const
可以表示任意的对象是常量
1 | const int a = 1; // a不能改变,是顶层const |
低层const
与指针和引用有关,表示,不能通过这个途径修改他们指向或者引用的变量
1 | const int *p = &a; // 指向a的指针,不能通过这个指针修改a的值,是底层const |
const
与参数传递
在参数传递时,顶层
const
会被忽略掉,因此下面这两个函数不能重载,因为他们忽略掉顶层const
后没有区别1
2void func(int i);
void func(const int i);可以使用非常量初始化底层
const
,但不能使用常量去初始化非底层const
1
2
3
4int a = 1;
const int b = 1;
const int &ref_1 = a; // 可以, 可以使用非常量初始化底层const
int &ret_2 = b; // 不可以, 不能使用常量去初始化非底层const非常量的引用必须是左值,常量的引用可以是左值,也可以是右值
1
2const int &a = 1; // 正确
int &b = 2; // 错误因此尽量将不会改变形参的函数的形参定义成底层
const
,因为这样定义我们可以使用字面量(rvalue)。