c++11 constxpr,編譯階段就計算出結果

  • 總覽

    • constexpr

      • 修飾變量,變量必須在執行前確認.

      • 修飾函數,表示入參和出參可能在編譯前確認.

    • 函數

      • constexpr修飾的函數裏面的都應該是constexpr.讓編程更加靈活.

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

      • 返回值不是const,僅僅用於修飾.

    • 變量

      • const類型的變量,執行前確認值.

      • 可能放在只讀區域.

      • constexprconst的加強版.

  • 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

      • 僅僅修飾變量不可變.

      • 不要求編譯時知道.

  • 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);
      }
      
      • 對象調用函數的結果作爲模板入參完成.

    • 注意

      • 編譯器做了這些計算工作,所以編譯時間會稍微長一點.

  • 總結

    • 對於變量,能用constexpr就儘量使用.

    • constexpr可以讓編程更加靈活,在很多場景中發光發熱.

    • 和宏定義打交道的地方,應該就可以用到constexpr.

    • constexpr修飾的函數,如果發生修改,可能會因爲其他人的使用導致編譯失敗.(開閉原則)

  • 發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章