总结来讲,就是在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)也是右值。