C++11新特性:constexpr變量和constexpr函數
本章將介紹constexpr變量和constexpr函數兩個知識點。在了解constexpr函數之前,首先要對常量表達式、constexpr變量、字面值類型、字面值常量的定義有一個清晰的了解。
先驗知識
1.常量表達式
指值不會改變並且在編譯過程中就能夠得到計算結果的值。
const int max_files = 20; //max_files是常量表達式
const int limit = max_files + 1; //limit是常量表達式
int staff_size = 27; //staff_size不是常量表達式,因為它的數據類型不是const
const int sz = get_size();
//sz不是常量表達式,因為get_size()只有到運行的時候才知道結果,除非它是constexpr修飾的(C++ 11標准)
2.constexpr變量
C++11新標准規定,允許將變量聲明為constexpr類型以便由編譯器驗證變量的值是否是一個常量表達式。如果不是,編譯器報錯。同時,聲明為constexpr的變量一定是常量,而且必須用常量表達式初始化。
constexpr int mf = 20; //正確,20是常量表達式
constexpr int limit = mf + 1; //正確,mf + 1是常量表達式
constexpr int sz = size(); //未知,若size()函數是一個constexpr函數時即正確,反之錯誤。
int i = 10;
constexpr int t = i; //錯誤,i不是常量
3.字面值類型
聲明constexpr變量時用到的類型被稱為字面值類型。算術類型、引用、指針、枚舉和一些特殊的類都屬於字面值類型,而IO庫、string類型則不屬於字面值類型,也就不能被定義為constexpr。
4.字面值常量
常量是指用const聲明或定義一個變量,使之成為常量。如const int bufSize = 512; #bufSize在程序中將不允許被修改,是常量
。而字面值常量是指只能用它的值來稱呼的,不能被修改的值,如4、3.1415926、0x24、"BEIJING"
。
5.指針與constexpr
對於指針而言,constexpr僅對指針本身有效,與指針所指對象無關。
const int *p = nullptr; //正確,p是一個指向整型常量的指針
constexpr int *q = nullptr; //正確,但q是一個指向 整數 的 常量指針
constexpr指針既可以指向常量也可以指向一個非常量。
constexpr int *np = nullptr; //正確,np是一個指向整數的常量指針,其值為空
int j = 0;
constexpr int i = 42;
//i和j都必須定義在函數體之外,否則constexpr指針無法指向。
constexpr const int *p = &i; /*p是常量指針,指向 整型常量i*/
constexpr int *p1 = &j; //p1是常量指針,指向 整數j(非常量)
constexpr函數
指能用於常量表達式的函數。該函數要遵循規定:函數的返回類型及所有形參的類型都得是字面值類型(聲明constexpr變量時用到的類型),並且函數體中必須有且只有一條return語句。
constexpr int new_sz() { return 42; }//constexpr函數
constexpr int foo = new_sz();
//在對變量foo初始化時,編譯器把對constexpr函數的調用替換成其結果值。為了能在編譯過程中隨時展開,constexpr函數被隱式地指定為內聯函數。
constexpr函數體內也可以包含其他語句,只要這些語句在運行時不執行任何操作即可。如空語句、類型別名、using聲明。
需要注意的是,我們允許constexpr函數的返回值並非一個常量???
這里需要弄清楚字面值類型的意義。。。
//如果arg是常量表達式,則scale(arg)也是常量表達式
constexpr size_t scale(size_t cnt){ return new_sz() * cnt; }
//當scale的實參是常量表達式時,它的表達式也是常量表達式,反之則不然
int arr[scale(2)]; //正確:scale(2)是常量表達式
int i = 2; //i不是常量表達式
int a2[scale(i)]; //錯誤:scale(i)不是常量表達式
注意,我們要把內聯函數和constexpr函數定義在頭文件中。