C++11 constexpr 有些事情,编译阶段就可以帮你做了

  1. 总览

    • constexpr

      • 修饰变量,变量必须在执行前确认.

      • 修饰函数,表示入参和出参可能在编译前确认.

    • 函数

      • constexpr修饰的函数里面的都应该是constexpr.让编程更加灵活.

      • 如果不是,就可以值能普通函数用.

      • 返回值不是const,仅仅用于修饰.

    • 变量

      • const类型的变量,执行前确认值.

      • 可能放在只读区域.

      • constexprconst的加强版.

  2. constexpr修饰的变量

    • 核心

      • 执行前必须能确认值.一般最晚链接前,共享库可以是加载.即虚拟地址也是可以的.

      • constexpr也是const类型,不能改. const的加强版本.

    • 编译时明确的好处

      • 数据可以存在只读区.嵌入式开发感知更强.

      • 可以用在需要完整常量表达式的场合. 还能做一下简单计算.

    • 编译器使用场景

      int main() {
         const int x = 5;
         int s[x];
      }
      
      • 指定数组长度.

      #include <array>
      int main() {
         constexpr int len = sizeof(int);
         std::array<int,len> a;
      }
      
      • 作为模板参数.

      #include <array>
      int main() {
         constexpr int len = sizeof(int);
         enum class T {
             START=len,
             MID,
             END
         };
      }
      
      • 给枚举类型赋值.

      #include <array>
      constexpr int len = sizeof(int);
      
      struct alignas(len) T {
         char s[10];
         int a;
      };
      
      int main() {
         T a;
      }
      
      • 指定字节对齐

      • 等等,其他场景都可以.

    • const

      • 仅仅修饰变量不可变.

      • 不要求编译时知道.

  3. constexpr修饰的函数

    • 核心

      • 仅仅时修饰: 入参都是constexpr的时候可能会生成constexpr的数据. 即编译前知晓.

      • 传入非constexpr类型的数据,则普通函数使用,返回值不是const. 这里和返回值类型无关.

    • 技巧

      • 肯定可以输出constexpr结果的函数,可以当成constexpr修饰的变量使用.

    • B内存总是A内存的平方

      #include<array>
      constexpr int getSize(int n) {
         return n * n;
      }
      
      int main() {
         constexpr int len = 10;
         std::array<int,len> a;
         std::array<int,getSize(len)> b;
      }
      
      • 模板类型必须在编译时确认,就需要借助constexpr.

      • 入参是constexpr,返回值也是.

    • c++11c++14constexpr函数的限制

      • C++11只允许有个return.

      • C++14可以有复杂的语句.

    • C++11

      #include<array>
      template<typename T> 
      void show(T&& t){
         t.error();
      }
      
      constexpr int getSize(int n) {
         return n ? getSize(n-1) + n : 0;
      }
      
      int main() {
         constexpr int len = 5;
         std::array<int,len> a;
         std::array<int,getSize(len)> b;
         show(b);
      }
      
      • 采用递归和三元运算的方式将其复杂化.

      • 这里的b的类型是with T = std::array<int, 15>&,即0+1+2+3+4+5 == 15.

      • 阅读性不强.

    • C++14允许较复杂的函数

      #include<array>
      template<typename T> 
      void show(T&& t){
         t.error();
      }
      
      constexpr int getSize(int n) {
         int sum = 0;
         for(int i = 0 ; i <= n ; i++ ) {
             sum+=i;
         }
         return sum;
      }
      
      int main() {
         constexpr int len = 5;
         std::array<int,len> a;
         std::array<int,getSize(len)> b;
         show(b);
      }
      
      • c++14得到一样的结果,但是C++11注释掉shwo也编不过.

    • 提醒

      • constexpr用来修饰函数而已,不修饰返回值,也修饰入参.

    • C++14加强

      • 允许class的成员函数和构造也可以用constexpr修饰.

      • c++11只允许修饰函数和内置类型.

    • C++14修饰类成员函数

      • 将一些值设置并提前计算出来,不需要在执行的时候再运算.

      #include<array>
      template<typename T> 
      void show(T&& t){
         t.error();
      }
      
      class T {
      public:
         constexpr int getSize(int n) {
             int sum = 0;
             for(int i = 0 ; i <= n ; i++ ) {
                 sum+=i;
             }
             return sum;
         }
      };
      int main() {
         constexpr int len = 5;
         std::array<int,len> a;
         std::array<int,T().getSize(len)> b;
         show(b);
      }
      
      • 成员函数的方式获取到了值.

      #include<array>
      template<typename T> 
      void show(T&& t){
         t.error();
      }
      
      class T {
      public:
         constexpr T(int a,int b):a(a),b(b){}
         constexpr int getSize(int n) {
             return a * b * n;
         }
      private:
         int a;
         int b;
      };
      int main() {
         constexpr int len = 5;
         std::array<int,len> a;
         std::array<int,T(2,3).getSize(len)> b;
         show(b);
      }
      
      • array的长度是30. 这里就是一个constexpr的对象,复杂类型,而非基础类型.

      • 三个涉及到的元素都是constexpr类型.

    • 对象constexpr

      • 即若干个constexpr类型的数据的组合.

      • 成员函数则是借助了constexpr,即若干个constexpr作为入参的函数.

      #include<array>
      template<typename T> 
      void show(T&& t){
         t.error();
      }
      
      class T {
      public:
         constexpr T(int a,int b):a(a),b(b){}
         constexpr int getSize(int n) const noexcept {
             return a * b * n;
         }
      private:
         int a;
         int b;
      };
      int main() {
         constexpr int len = 5;
         constexpr T t{2,3};
         std::array<int,len> a;
         std::array<int,t.getSize(len)> b;
         show(b);
      }
      
      • 对象调用函数的结果作为模板入参完成.

    • 注意

      • 编译器做了这些计算工作,所以编译时间会稍微长一点.

  4. 总结

    • 对于变量,能用constexpr就尽量使用.

    • constexpr可以让编程更加灵活,在很多场景中发光发热.

    • 和宏定义打交道的地方,应该就可以用到constexpr.

    • constexpr修饰的函数,如果发生修改,可能会因为其他人的使用导致编译失败.(开闭原则)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值