C++ const及constexpr关键字
最近复习了一下关于const和constexpr的用法,在这里总结一下。错漏之处,请不吝指正。
const关键字
c中的const
1.变量定义
const int a = 10;
使用这种方式定义的变量,它的值不会改变,在其整个作用域中固定。这也就是说,const
变量只会被初始化一次(可以使用变量或函数的返回值来初始化const变量)。
值得一提的是,const
变量可以用来初始化数组,这也就说明了,const
类型定义的数据,编译器是将其作为常量处理的。
2.const与指针
const int* p_1;
int const* p_2;
int* const p_3;
const int* const p_4;
int const* const p_5;
const
配合指针的使用通常有以上几种场景。通常我们认为前两种情况是相同的,都是限制指针指向位置的变量不可变,而指针的指向是可变的;第三种情况表示,指针的指向是不可变的,而指针指向位置的变量是可变的。
最后两种情况是以上两种用法的结合,不难想象,其代表的含义就是指针指向位置的变量不可变,同时指针的指向也是不可变的。
3. 修饰函数形参
size_t strlen ( const char * str );
int strcmp ( const char * str1, const char * str2 );
char * strcat ( char * destination, const char * source );
char * strcpy ( char * destination, const char * source );
int system (const char* command);
int puts ( const char * str );
int printf ( const char * format, ... );
引用部分标准库中的函数定义,可以看到,很多使用const
关键字对形参做出限制。其作用与修饰变量类似,表示某个形参不能被修改,或是某个形参指针指向不能被修改。目的是为了提高函数的健壮性。同时也告诉程序员,使用本函数不会对传入的某些参数做出修改。
4. 修饰函数返回值
const char * FUN(void);
使用这种方式,声明的函数,表示函数返回的指针不能被修改。同时,改返回值的接收指针也必须是const
修饰的指针,否则会报错。
c++中的const
主要是static
在类中的使用。在类中修饰变量与类外修饰变量的使用方式类似,此处不再赘述。主要介绍使用const
修饰类成员函数的用法。
1.const修饰类成员函数
class Stack {
public:
void push(int const& item);
void pop();
int top() const;
bool empty() const;
private:
vector<int> elems;
};
const 修饰类成员函数,其目的是防止成员函数修改被调用对象的值,如果我们不想修改一个调用对象的值,所有的成员函数都应当声明为 const
成员函数
注意:const
关键字不能与 static
关键字同时使用,因为 static
关键字修饰静态成员函数,静态成员函数不含有this
指针,即不能实例化,const
成员函数必须具体到某一实例。
constexpr关键字
constexpr是c++11新添加的特征,目的是将运算尽量放在编译阶段,而不是运行阶段。这个从字面上也好理解,const是常量的意思,也就是后面不会发生改变,因此当然可以将计算的过程放在编译过程。constexpr可以修饰函数、结构体。
1.constexpr修饰变量
const int bb = 1;
constexpr int a = bb + 2;
定义变量时可以用 constexpr
修饰,从而使该变量获得在编译阶段即可计算出结果的能力。
使用 constexpr
修改普通变量时,变量必须经过初始化且初始值必须是一个常量表达式。
2.constexpr修饰函数
constexpr int sum(const int _x, const int _y)
{
return _x + _y;
}
简单的来说,如果其传入的参数可以在编译时期计算出来,那么这个函数就会产生编译时期的值。但是,传入的参数如果不能在编译时期计算出来,那么constexpr
修饰的函数就和普通函数一样了。不过,使用constexpr
修饰函数是有一定要求限制的,如果函数体适用于constexpr
函数的条件,可以尽量加上constexpr
。
使用constexpr 的限制
- 在
constexpr
函数中只能调用其它constexpr
函数 - 在
constexpr
函数中只能使用全局constexpr
变量 - 函数中只能有一个
return
语句(但允许包含typedefs、 using declaration && directives、静态断言
等)
3.constexpr修饰结构体
class Circle
{
public:
constexpr Circle(double radius) :radius(radius) {}
const double PI = 3.14;
const double radius;
};
int main()
{
constexpr Circle c = {4};
cout << c.radius << endl;
return 0;
}
可以看到,如上所示就可以使用constexpr
修饰一个类的构造函数。值得注意的是,constexpr
修饰类的构造函数时,要求该构造函数的函数体必须为空,且采用初始化列表的方式为各个成员赋值时,必须使用常量表达式。
其实 constexpr
也可以修饰类中的成员函数,只不过此函数必须满足前面提到的 3 个条件。
4.constexpr修饰模板
constexpr
可以修饰模板函数,但由于模板中类型的不确定性,因此模板函数实例化后的函数是否符合常量表达式函数的要求也是不确定的。
针对这种情况下,C++11 标准规定,如果 constexpr
修饰的模板函数实例化结果不满足常量表达式函数的要求,则 constexpr
会被自动忽略,即该函数就等同于一个普通函数。