最新在弄android ndk相關的,驚奇的發現最新的ndk10的版本已經gcc4.9了,我印象中,gcc4.8就支持C++0x11,14的支持,gcc再次走到了llvm的前面,LLVM最新的版本3.4.2應該只支持c++ 11,如果是同樣的c++代碼我一直認為llvm的效率會明顯強過gcc.
廢話不多說,讓我們開始學習c++ 11吧,說實話我之前一直都很抗拒c++新的語法,感覺太難接受了,現在看來不熟悉也不行了。
常量表達式(constexpr)
常量表達式機制是為了:
提供了更多的通用的值不發生變化的表達式
允許用戶自定義的類型成為常量表達式
提供了一種保證在編譯期完成初始化的方法(可以在編譯時期執行某些函數調用)
基本語法:
1.修飾常量表達式
int var1 = 100;
const int const_var2 = 200;
const int const_var3 = var1;
constexpr int constexpr_var1 = 3 + const_var2 * 4; //成立
// constexpr int constexpr_var2 = 3 + var1 * 4; //錯誤
// constexpr int constexpr_var3 = 3 + const_var3 * 4; //錯誤
2.修飾函數
constexpr int Inc(int i) {
return i + 1;
}
constexpr int a = Inc(1); // 正確
constexpr int b = Inc(cin.get()); // 錯誤
constexpr int c = a * 2 + 1; // 正確,但是如果沒有Inc(1),也是錯誤的。
constexpr修飾的值要有初始值,和const不同的是初始化的值可以一個表達式,但是這個表達式的值必須是在編譯期間就能確定值的。
3.修飾類或者結構體
struct A {
constexpr A(int xx, int yy): x(xx), y(yy) {}
int x, y;
};
constexpr A aa(1, 2);
constexpr int ccc = aa.x;
enum {SIZE_X = aa.x, SIZE_Y = aa.y};//llvm報錯
Reference to local variable 'aa' declared in enclosing function 'main'
如果把constexpr A aa(1, 2);寫成全局的就Ok,但是某些編譯器並不會報錯,我個人認為這個llvm編譯器不太合理的地方,如果緊緊是aa是一個局部變量就不允許,但是aa本身的值是在編譯的時候就確認了的。
個人的理解就是constexpr擴展了常量的含義,從語法上支持更多的常量定義,對比宏又有更好的類型檢測和安全性,更強的約束語法帶來更好的代碼優化。
無意中在csdn論壇上看見大神的一段短話,摘錄下來,很值的體會
constexpr:不光是可以取代模板是某些常量的表達更簡潔,其實一個決定性的作用是支持地址類常量。這恰好補上了模板缺失的部分。比如有一個字符串常量"abc",很自然的可以認為其中的元素也是常量地址,對一個有編譯期內容的常量地址取值理論上可以在編譯器確定結果,但實際上按舊語法卻不能直接拿去做為常量使用而是當作變量。
union帶構造函數、支持帶用戶定義構造函數的類作為其成員,本意是用來支持某種多型變量,比如根據某個標志決定一個這樣的union當前是什么類型。濫用則會導致數據錯誤。
noexcept支持推導,而容器元素在支持右值引用的情況下這類推導是很重要的。右值引用可以減少深拷貝的需求,但是在某些情況下會破壞強異常安全保證。利用noexcept推導來決定一個復雜類型作為容器元素的時候到底適合用移動還是適合用普通的拷貝策略來保證強異常安全。比如一個類型如果不支持無異常的移動(自身或任一基類或者數據成員的移動構造函數不支持noexcept,因此需要用到推導),則這個類型不適合移動而只能使用拷貝實現異常安全