一. const 和constexpr的区别 (一)修饰变量时,const为“运行期常量” ,即运行期数据是只读的。而constexpr为“编译期”常量 ,这是const无法保证的。两者都是对象和函数接口的组成部分。
(二)修饰函数时,与const关键字相比,constexpr关键字不仅可以修饰变量和指针,还可以修饰函数(含构造函数) 。注意constexpr用于定义自定义类的对象时,要求该类具有常量构造函数,而使用const定义类对象时,则无此要求。
(三)两者在修饰指针时 ,行为有所差异。const放在*号前,表示指针指向的内容不能被修改.const放在*号后,表示指针不能被修改 ;而constexpr关键字只能放在*号前面,并且表示指针所指的内容不能被修改 。
二、常量表达式函数 (一)构成constexpr函数的条件
1. 函数体只有单一的return语句(可以通过“:”或递归来扩展)。在C++14中这条己经不再是限制。
2. 函数体必须有返回值(C++11中要求不能是void函数,但C++14己不再限制)
3、constexpr函数内部不能调用非常量表达式的函数,会造成编译失败。
4. return返回语句表达式中不能使用非常量表达式的函数、全局数据,且必须是一个常量表达式。
(二)注意事项
1. 在使用常量表达式函数前,必须先被定义。不能先声明,然后在函数调用后再定义。
2. constexpr函数在调用时若传入的实参均为编译期己知的,则返回编译期常量 。只要任何一个实参在编译期未知,则它的运作与普通函数无异 ,将产生运行期结果 。
3. constexpr函数的构成条件不满足时,就会变成一个普通的函数。同时constexpr函数可以同时应用于编译期语境或运行期语境 (编译期语境如constexpr int a = func_constexpr(x, y)。运行期语境如int a = func_constexpr(x, y))。
【编程实验】const和constexpr的差异
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #include <iostream> #include <array> using namespace std ;int g_count = 0 ;int normalfunc (int x) { return x; } constexpr int func1 (int x) { return x + 2 ; } constexpr void func2 () {} constexpr int func3 () ; constexpr int pow (int base, int exp ) { auto ret = 1 ; for (int i = 0 ; i < exp ; ++i) { ret *= base; } return ret; } int main () { int x = 0 ; const int y = 0 ; constexpr int a = 2 ; constexpr int b = a + 4 ; constexpr int c = y + 1 ; const auto n = x; constexpr auto N = 10 ; std ::array <int , N> arr2; std ::array <int , c> arr3; constexpr auto exp = 5 ; std ::array <int , pow (3, exp )> arr4; constexpr int * ptr2 = &g_count; *ptr2 = 100 ; int var1 = func3(); constexpr int c1 = func1(N); int c2 = func1(x); int c3 = func1(N); return 0 ; } constexpr int func3 () { return 0 ; }
三、constexpr的应用 (一)定义自定义类的constexpr对象。
1. 自定义类的构造函数须为constexpr函数 。
2. constexpr不能用于修饰virtual函数。因为virtual是运行时的行为,与constexpr的意义冲突。
3. C++11中被声明为constexpr成员函数会自动设为const函数,但C++14中不再自动设为const函数。
(二)函数模板: 实例化后的函数是否为constexpr函数,在编译期是不确定的,取决于传入的实参是否为constexpr类型 。
(三)constexpr类型的函数递归
1. 利用constexpr进行编译期运算的编程方式称为constexpr元编程
2 .基于模板编译期运算的编程方式,叫模板元编程。
【编程实验】constexpr的应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 #include <iostream> using namespace std ;class Point { double x, y; public : constexpr Point(double x=0, double y=0) noexcept : x(x),y(y){} constexpr double getX () const noexcept { return x;} constexpr double getY () const noexcept { return y;} constexpr void setX (double newX) noexcept { x = newX; } constexpr void setY (double newY) noexcept { y = newY; } }; constexpr Point midpoint (const Point& p1, const Point& p2) noexcept { return { (p1.getX() + p2.getX()) / 2 , (p1.getY() + p2.getY()) / 2 }; } constexpr Point reflection (const Point& p) noexcept { Point ret; ret.setX(-p.getX()); ret.setY(-p.getY()); return ret; } template <typename T>constexpr T func (T t) { return t; } struct NotLiteral { int i; NotLiteral():i(5 ){} }; constexpr int Fib (int n) { return (n == 1 ) ? 1 : ((n == 2 ) ? 1 : Fib(n-1 ) + Fib(n -2 )); } template <long N>struct Fibonacci { static const long val = Fibonacci<N - 1 >::val + Fibonacci<N - 2 >::val; }; template <> struct Fibonacci <2> { static const long val = 1 ; };template <> struct Fibonacci <1> { static const long val = 1 ; };template <> struct Fibonacci <0> { static const long val = 0 ; };void printArray (int a[], int len) { cout << "Fibonacci: " ; for (int i=0 ; i<len; ++i) { cout << a[i] << " " ; } cout << endl ; } int main () { constexpr Point p1 (9.4 , 27.7 ) ; constexpr Point p2{ 28.8 , 5.3 }; constexpr auto mid = midpoint(p1, p2); constexpr auto reflectedMid = reflection(mid); NotLiteral n1; NotLiteral n2 = func(n1); constexpr int a = func(1 ); int fib1[]{ Fib(11 ), Fib(12 ), Fib(13 ), Fib(14 ) }; printArray(fib1, 4 ); int fib2[] = { Fibonacci<11 >::val, Fibonacci<12 >::val, Fibonacci<13 >::val, Fibonacci<14 >::val }; printArray(fib1, 4 ); return 0 ; }