運行時常量(const)和編譯時常量(constexpr)

在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的成員函數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章