總結來講,就是在c++11以前,要實現編譯期數值計算須要繁瑣的模板元編程。在c++11 中,能夠是函數,在一句ruturn 語句中進行求值,函數中既不能有變量也不能有分之判斷語句,限制較多。在C++17以後,則取消了大部分限制,好比能夠有變量,能夠有分支判斷語句,但不能有goto,asm,try等語句。具體能夠參考cppreference。c++
準確的說,constexpr函數是一種在編譯期和運行期都能被調用並執行的函數。出於constexpr函數的這個特色,在C++11以後進行數值計算時,不管在編譯期仍是運行期咱們均可以統一用一套代碼來實現。編譯期和運行期在數值計算這點上獲得了部分統一。express
當且僅當E指的是已經具備使其可在E外部訪問的標識(地址,名稱或別名)的實體時,表達式E屬於左值類別。編程
#include <iostream> int i=7; const int& f(){ return i; } int main() { std::cout<<&"www"<<std::endl; // This address ... std::cout<<&"www"<<std::endl; // ... and this address are the same. "www"; // The expression "www" in this row is an **lvalue expression**, because it refers to the same entity ... "www"; // ... as the entity the expression "www" in this row refers to. i; // The expression i in this row is an lvalue expression, because it refers to the same entity ... i; // ... as the entity the expression i in this row refers to. int* p_i=new int(7); *p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ... *p_i; // ... as the entity the expression *p_i in this row refers to. const int& r_I=7; r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ... r_I; // ... as the entity the expression r_I in this row refers to. f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ... i; // ... as the entity the expression f() in this row refers to. return 0; }
若表達式E屬於xvalue類別,當且僅當它知足:
-不管是隱式調用仍是顯示調用,調用一個函數的結果返回一個對要返回的對象類型的引用的rvalue函數
int&& f(){ return 3; } int main() { f(); // 表達式 f() 是xvalue ,由於 f() 的返回類型是一個對象類型的引用的 rvalue. return 0; }
-或者,右值(rvalue)引用對象類型的castui
int main() { static_cast<int&&>(7); // 表達式static_cast<int&&>(7) , 其是右值引用對象類型的 cast. std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7). return 0; }
-類成員訪問表達式指定 非引用類型的非靜態數據成員, 其中對象表達式是 xvaluethis
struct As { int i; }; As&& f(){ return As(); } int main() { f().i; // f().i 是 xvalue, 由於 As::i 是 non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category. return 0; }
#include <functional> struct As { int i; }; As&& f(){ return As(); } int main() { f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object. As&& rr_a=As(); rr_a; // rr_a 是 lvalue category,由於它指的是一個命名的 rvalue 對象引用 std::ref(f); // n std::ref(f) 表達式是 lvalue , 由於它指的是一個命名的 rvalue 對象引用 return 0; }
當且僅當E既不屬於左值也不屬於xvalue類別時,表達式E屬於prvalue類別。.net
struct As { void f(){ this; // this 是 **prvalue** 表達式。 注意:this 不是一個變量 } }; As f(){ return As(); } int main() { f(); // f() 表達式屬於 prvalue category, 其既不屬於 lvalue 也不屬於 xvalue 類 return 0; }
當且僅當E屬於xvalue類別或屬於prvalue類別時,表達式E屬於rvalue類別。
請注意,此定義表示當且僅當E指的是沒有任何標識使其可在E以外訪問的實體時,表達式E屬於右值類別。指針
當且僅當E屬於lvalue類別或xvalue類別時,表達式E屬於glvalue類別。c++11
一個實用的規則
Scott Meyers 已出版的經驗的一個很是有用的規則,從左值右值的區別。
若是能夠獲取表達式的地址,則表達式爲左值。 若是表達式的類型是左值引用(例如,T&或const T&等),則該表達式是左值。 不然,表達式是右值。從概念上(一般也是實際上),rvalues對應於臨時對象,例如從函數返回的或經過隱式類型轉換建立的臨時對象。大多數文字值(例如,10和5.3)也是右值。