在c++中,我們會常常遇到常量的概念。常量表示該值不可修改。如:
const int i=3;//i爲常量
const 還可以修飾函數參數,函數返回值,函數本身,類等。在不同的條件下,const有不同的意義,大多數情況const描述的都是”運行時常量概念“,既具有運行時數據不可更改性。不過有時候,我們需要編譯時期的常量性,這是const關鍵字無法保證的。如:
const int getconst()
{
return 1;
}
void testfun(int n)
{
int arr[getconst()] = { 0 };//無法通過編譯
switch (n)
{
case getconst()://無法通過編譯
{
//.......
}break;
default:
break;
}
}
那如果想要獲得編譯時期的常量,有沒有辦法呢?最簡單的方法,可以使用c語言中的宏代替getconst函數。
#define getconst 1
當然這種簡單粗暴的做法即使有效,也會把C++來回“石器時代”。C++11中對編譯時期常量 引入了constexpr ,既常量表達式(const expression)。上面的getconst函數就可以用下面的聲明方法:
constexpr int getconst()
{
return 1;
}
即在函數表達式前面加上constexpr關鍵字即可。有了常量表達式這樣的聲明,編譯器就可以在編譯時期對getconst表達式進行值計算,從而將其視爲一個編譯時期的常量(可能)。在C++11中,常量表達式實際上不僅僅用於函數,還可以作用於數據聲明,類的構造等。
1.constexpr修飾函數--常量表達式函數
在函數返回值類型前加上關鍵字constexpr來使其成爲常量表達式函數。不過需要注意:
a.函數必須返回值(不能是void函數 ,也沒意義)。 如:constexpr void f();這樣的不返回值得函數就不能是常量表達式。因爲無法獲得常量得常量表達式時不被認可得。
b.在使用前必須已有定義。 對於普通函數而言。調用函數只需要有函數的聲明就夠了,但是常量表達式函數的 使用 不同。使用講的時編譯時值的計算,而調用時運行時期概念
constexpr int f();//聲明
int a = f();//調用 運行時期
const int b = f();//調用
constexpr int c = f();//無法通過編譯 編譯器無法確定f()值 使用 編譯時期
constexpr int f() { return 1; };//定義
constexpr int d = f();//使用
c.return 返回值語句表達式不能使用非常量表達式的函數,全局函數,且必須是一個常量表達式
const int e(){return 1;};
constexpr int f(){return e();};//無法通過編譯
或形如:
int g =1;
constexpr int f(){return g;};//無法通過編譯
2.constexpr修飾變量 -- 常量表達式值
a.修飾基本數據類型
通常情況下,常量表達時值必須被一個常量表達式賦值,即在使用前必須被初始化。
const int a=1;
constexpr int b =1;
多數情況下上面兩者沒有區別,但是a在全局中編譯器會爲a產生值,而b不一定會爲其產生值,僅將其當做編譯時期的值,只有代碼顯示地使用了它的值纔會產生值。
b.修飾自定義類型
當修飾自定義類型時注意兩點:一是 構造函數加constexpr修飾 函數體必須爲空;二是 初始化列表只能有常量表達式來賦值如:
struct MyStruct
{
constexpr MyStruct(int x) :i(x) {};
constexpr int getivalue(){return i};
private:
int i;
};
constexpr MyStruct ms(1);
constexpr MyStruct ms2 = { 2 };
總結:constexpr體現的是編譯時期的“常量性”, 如不能作用於virtual的成員函數