zoukankan      html  css  js  c++  java
  • 【转】constexpr变量

    常量表达式

      常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。

      一个对象(或表达式)是不是常量表达式由它的数据类型和初始值共同决定,例如:

    1 const int max_files = 20;    //max_files是常量表达式
    2 const int limit = max_files + 1;    //limit是常量表达式
    3 int staff_size = 27;    //staff_size不是常量表达式
    4 const int sz = get_size();    //sz不是常量表达式

      尽管staff_size的初始值是个字面值常量,但由于它的数据类型只是一个普通int而非const_int,所以它不属于常量表达式。另一方面,尽管sz本身是一个常量,但它的具体值直到运行时才能获取,所以也不是常量表达式。

    constexpr变量

      在一个复杂系统中,很难(几乎肯定不能)分辨一个初始值到底是不是常量表达式。

      constexpr是C++11开始提出的关键字,其意义与14版本有一些区别。

      C++11中的constexpr指定的函数返回值和参数必须保证是字面值类型(literal type,常用的算术类型、引用和指针都属于字面值类型)。而且必须有且只有一行return代码,这给函数的设计者带来了更多的限制,比如通常只能通过return 三目运算符 + 递归来计算返回的字面值。

      而C++14中只要保证返回值和参数是字面值就行了,函数体中可以加入更多的语句,方便更灵活的运算。

      很多人都把constexpr和const相比较。

      其实,const并不能代表“常量”,它仅仅是对变量的一个修饰,告诉编译器这个变量只能被初始化,且不能被直接修改(实际上可以通过堆栈溢出等方式修改)。而这个变量的值,可以在运行时也可以在编译时指定。

      constexpr可以用来修饰变量、函数、构造函数。一旦以上任何元素被constexpr修饰,那么等于说是告诉编译器 “请大胆地将我看成编译时就能得出常量值的表达式去优化我”。

    如:

    1 const int func() {
    2     return 10;
    3 }
    4 void main(){
    5   int arr[func()];
    6 }

      对于func() ,胆小的编译器并没有足够的胆量去做编译期优化,哪怕函数体就一句return 字面值;

    1 constexpr int func() {
    2     return 10;
    3 }
    4 void main(){
    5   int arr[func()];
    6 }

      编译期大胆地将func()做了优化,在编译期就确定了func计算出的值10而无需等到运行时再去计算。

      这就是constexpr的第一个作用:给编译器足够的信心在编译期去做被constexpr修饰的表达式的优化。

      constexpr还有另外一个特性,虽然它本身的作用之一就是希望程序员能给编译器做优化的信心,但它却猜到了自己可能会被程序员欺骗,而编译器并不会对此“恼羞成怒”中止编译,如:

    1 constexpr int func(const int n){
    2   return 10+n;
    3 }
    4 void main(){
    5  const  int i = cin.get();
    6  cout<<func(i);
    7 }
      程序员告诉编译器尽管信心十足地把func当做是编译期就能计算出值的程式,但却欺骗了它,程序员最终并没有传递一个常量字面值到该函数。没有被编译器中止编译并报错的原因在于编译器并没有100%相信程序员,当其检测到func的参数是一个常量字面值的时候,编译器才会去对其做优化,否则,依然会将计算任务留给运行时。
    基于这个特性,constexpr还可以被用来实现编译期的type traits,比如STL中的is_const的完整实现:
     1 template<class _Ty,
     2     _Ty _Val>
     3 struct integral_constant
     4 {   // convenient template for integral constant types
     5     static constexpr _Ty value = _Val;
     6 
     7     typedef _Ty value_type;
     8     typedef integral_constant<_Ty, _Val> type;
     9 
    10     constexpr operator value_type() const noexcept
    11     {   // return stored value
    12         return (value);
    13     }
    14 
    15     constexpr value_type operator()() const noexcept
    16     {   // return stored value
    17         return (value);
    18     }
    19 };
    20 
    21 typedef integral_constant<bool, true> true_type;
    22 typedef integral_constant<bool, false> false_type;
    23 
    24 template<class _Ty>
    25 struct is_const
    26     : false_type
    27 {   // determine whether _Ty is const qualified
    28 };
    29 
    30 template<class _Ty>
    31 struct is_const<const _Ty>
    32     : true_type
    33 {   // determine whether _Ty is const qualified
    34 };
    35 int main() {
    36 
    37     static_assert(is_const<int>::value,"error");//error
    38     static_assert(is_const<const int>::value, "error");//ok
    39     return 0;
    40 }

      转自《C++11/14 constexpr 用法

  • 相关阅读:
    linux命令: mount
    梳理一下uboot是如何从nandflash挂载文件系统的
    MDK的优化应用
    面向对象设计思想:面向对象设计的基本原则
    问题
    nodejs安装不了和npm安装不了的解决方法
    []: secureCRT连接ubuntu问题- The remote system refused the connection
    字符设备驱动[深入]:linux cdev详解
    使用MDK将STM32的标准库编译成lib使用
    liteos任务(二)
  • 原文地址:https://www.cnblogs.com/codingmengmeng/p/14172169.html
Copyright © 2011-2022 走看看