国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

性能優化利器之Constexpr

開發 開發工具
說明符constexpr?是自C++11引入,我相信很多人跟我一樣,在第一次接觸這個的時候,會很容易和const混淆。

你好,我是雨樂!

最近在升級系統和進行一些性能優化,業余時間也看一些技術書籍和視頻,看了下上次更新文章的時間,大致在一個月前了,確實有點久了,所以趕緊拾起來,不能讓大伙忘了我不是??。

今天,聊聊在升級過程中的一個比較重要的優化點-編譯期優化。

概述

說明符constexpr是自C++11引入,我相信很多人跟我一樣,在第一次接觸這個的時候,會很容易和const混淆。

從概念上理解的話,constexpr即常量表達式,重點在表達式字段,用于指定變量或函數可以在常量表達式中使用,可以(或者說一定)在編譯時求值的表達式,而const則為了約束變量的訪問控制,表示運行時不可以直接被修改,其往往可以在編譯期和運行時進行初始化。

前面提到了constexpr是在編譯階段進行求值,那么也就是說在程序運行之前,就已經計算完成,這種無疑大大提升了程序的運行效率。因此提升運行效率就是C++11引入constexpr說明符的目的,也就是說能在編譯階段做的事情就絕不放在運行期做。

變量

代碼如下:

example1.cc

int main() {
    const int val = 1 + 2;
    return 0;
}

上述代碼匯編結果如下:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 3
        mov     eax, 0
        pop     rbp
        ret

從上述匯編結果可以看出,在編譯階段就將val賦值成3,也就是說在編譯階段完成了求值操作。

再看另外一個示例2:

example2.cc

int Add(const int a, const int b) {
    return a + b;
}

int main() {
    const int val = Add(1, 2);
    return 0;
}

同樣的,其匯編如下:

Add(int, int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     DWORD PTR [rbp-8], esi
        mov     edx, DWORD PTR [rbp-4]
        mov     eax, DWORD PTR [rbp-8]
        add     eax, edx
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     esi, 2
        mov     edi, 1
        call    Add(int, int)
        mov     DWORD PTR [rbp-4], eax
        mov     eax, 0
        leave
        ret

分析上述匯編,發現并沒有在編譯階段進行求值,所以也就是說上述的求值過程將會延后至編譯期進行。

好了,既然示例一(使用const)可以在編譯期進行求值,而constexpr也可以在編譯期求值,那么直接用constexpr替換示例一種的const是否可行?

example3.cc

int main() {
    constexpr int val = 1 + 2;
    return 0;
}

接著看下匯編代碼:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 3
        mov     eax, 0
        pop     rbp
        ret

呃??,與示例一完全一樣。。。

在上面示例2中,通過匯編代碼發現其是在運行期求值,那么有沒有辦法在編譯期求值呢?那就是使用constexpr表達式:

example4.cc

constexpr int Add(const int a, const int b) {
    return a + b;
}

int main() {
    const int val = Add(1, 2);
    return 0;
}

匯編如下:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 3
        mov     eax, 0
        pop     rbp
        ret

有沒有發現很眼熟,對,跟示例1和示例3的結果一樣,該代碼較示例2的唯一區別是多了個constexpr說明符,但將求值時期從運行期放到了編譯期,可想而知,效率提升那是杠杠的。。。??

函數

constexpr也可以修飾普通函數或者成員函數,其實這塊在上一節已經有提過,示例如下:

constexpr int Add(const int a, const int b) {
    return a + b;
}

int main() {
    const int val = Add(1, 2);
    int val1 = 3;
    int val2 = Add(val, val1);
    return 0;
}

匯編如下:

Add(int, int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     DWORD PTR [rbp-8], esi
        mov     edx, DWORD PTR [rbp-4]
        mov     eax, DWORD PTR [rbp-8]
        add     eax, edx
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 3
        mov     DWORD PTR [rbp-8], 3
        mov     eax, DWORD PTR [rbp-8]
        mov     esi, eax
        mov     edi, 3
        call    Add(int, int)
        mov     DWORD PTR [rbp-12], eax
        mov     eax, 0
        leave
        ret

從上述匯編代碼可以看出,val的求值是在編譯階段,而val2的求值則是在運行階段,這是因為其引入了一個非const變量val1。

通過本示例,可以看出,將函數聲明為constexpr可以提示效率,讓編譯器來決定是在編譯階段還是運行階段來進行求值,當然了,如果想了解在編譯階段求值的各種細節規則,請參考constexpr in cppreference。

if語句

如果您目前使用C++11進行編碼,那么需要仔細閱讀本節,這樣可以為將來的版本升級打好基礎;如果您正在使用C++17進行編碼,那么更得閱讀本節,相信讀完本節后,會有一個不一樣的認識??。

自C++17起,引入了if constexpr語句,在本節中,將借助SFINAE 和 std::enable_if來實現一個簡單的Square功能,最后借助if constexpr對代碼進行優化(如果對SFINAE 和 std::enable_if不是很了解的,建議自行閱讀哈)。

如果有個需求,實現一個Add函數,其既支持算術類型又支持用戶自定義類型:

template <typename T>
struct Number {
    Number(const T& _val) :
        value(_val) {}

    T value;
};

template<typename T>
T Square(const T& t) {
    return t + t;
}

int main() {
  int i = 5;
  float f = 5.0;
  bool b = true;
  Number<int> n(5);

  auto res = Square(i); // 調用int Add(int);
  auto res2 = Square(f); // 調用 float Add(float);
  auto res3 = Square(b);  // call bool Square(bool);
  auto res4 = Square(n); //編譯失敗,因為Number<>沒有提供operator*操作
}

上述代碼編譯出錯,因為Number<>沒有提供operator*操作,所以這個時候第一個想法是修改Square函數,如下:

template<typename T>
T Square(const T& t) {
    if (std::is_arithmetic<T>::value) {
        return t * t;
    } else {
        return t.value * t.value;
    }
}

在上述代碼中,如果T是算數類型,則直接進行*操作,否則取其value進行*操作。

將上述代碼進行編譯,報錯如下:

example5.cc: In instantiation of ‘T Square(const T&) [with T = int]’:
example5.cc:26:20:   required from here
example5.cc:16:18: error: request for member ‘value’ in ‘t’, which is of non-class type ‘const int’
   16 |         return t.value * t.value;
      |                ~~^~~~~
example5.cc:16:28: error: request for member ‘value’ in ‘t’, which is of non-class type ‘const int’
   16 |         return t.value * t.value;
      |                          ~~^~~~~
....

以Square(i)為例,這是因為在編譯的時候,會嘗試int.value操作,顯然int.value不存在,這就導致了上述的錯誤輸出,為了更為清楚的顯示本錯誤,將Square()修改如下:

int Square(const int& t) {
    if (true) {
        return t * t;
    } else {
        return t.value * t.value;
    }
}

這樣就能很清楚的知道為什么編譯失敗了,因為在代碼中存在t.value * t.value操作,而對于一個int來說并沒有value這個變量,所以編譯失敗。

為了解決這個問題,我們嘗試引入std::enable_if操作,如下:

template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type Square(const T& t) {
    return t * t;
}

template<typename T>
typename std::enable_if<! std::is_arithmetic<T>::value, T>::type Square(const T& t) {
    return t.value * t.value;
}

現在有兩個函數模板,如果是算術類型,則調用第一個,否則調用第二個,完整代碼如下:

#include <type_traits>

template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type Square(const T& t) {
    return t * t;
}

template<typename T>
typename std::enable_if<! std::is_arithmetic<T>::value, T>::type Square(const T& t) {
    return t.value * t.value;
}

template <typename T>
struct Number {
    Number(const T& _val) :
        value(_val) {}

    T value;
};

int main() {
  int i = 5;
  float f = 5.0;
  bool b = true;
  Number<int> n(5);

  auto res = Square(i); // 調用int Add(int);
  auto res2 = Square(f); // 調用 float Add(float);
  auto res3 = Square(b);  // call bool Square(bool);
  auto res4 = Square(n); // 成功
  
  return 0;
}

上述代碼編譯成功。

在上述代碼中,為了編譯成功,我們引入了兩個Square()模板函數借助std::enable_if來實現,代碼上多少有點冗余,在這個時候,本節的主角if constexpr 出場,完整代碼如下:

#include <type_traits>
template<typename T>
T Square(const T& t) {
    if constexpr (std::is_arithmetic<T>::value) {
        return t * t;
    } else {
        return t.value * t.value;
    }
}

template <typename T>
struct Number {
    Number(const T& _val) :
        value(_val) {}

    T value;
};

int main() {
  int i = 5;
  float f = 5.0;
  bool b = true;
  Number<int> n(5);

  auto res = Square(i); // 調用int Add(int);
  auto res2 = Square(f); // 調用 float Add(float);
  auto res3 = Square(b);  // call bool Square(bool);
  auto res4 = Square(n); // 成功
  
  return 0;
}

編譯成功。

我們借助一個Square()函數模板以及更加符合編碼習慣的if語句就能解決上面的問題,且比使用std::enable_if方式更為優雅和符合閱讀習慣,進而提高代碼的可閱讀性。

責任編輯:武曉燕 來源: 高性能架構探索
相關推薦

2020-06-10 10:40:03

JavaJMH字符串

2021-07-29 14:20:34

網絡優化移動互聯網數據存儲

2021-11-29 11:13:45

服務器網絡性能

2022-02-16 14:10:51

服務器性能優化Linux

2024-04-03 09:12:03

PostgreSQL索引數據庫

2018-01-09 16:56:32

數據庫OracleSQL優化

2019-12-13 10:25:08

Android性能優化啟動優化

2009-06-30 11:23:02

性能優化

2025-01-20 09:09:59

2011-07-11 15:26:49

性能優化算法

2013-02-20 14:32:37

Android開發性能

2023-04-10 11:18:38

前端性能優化

2011-06-14 11:14:10

性能優化代碼

2021-07-16 23:01:03

SQL索引性能

2011-06-14 14:17:23

性能優化系統層次

2013-09-17 10:32:08

Android性能優化數據庫

2015-09-16 14:37:50

Android性能優化運算

2015-09-16 13:54:30

Android性能優化渲染

2011-06-14 13:48:07

性能優化工具

2023-07-05 15:55:26

性能優化開發分析工具
點贊
收藏

51CTO技術棧公眾號

久久精品这里热有精品| 国产主播福利在线| 国产麻豆精品一区二区| 激情视频一区| 精品国产成人在线| 欧美国产激情| 一本色道久久加勒比精品| 欧亚精品中文字幕| 99在线免费视频| 欧美欧美黄在线二区| 一区二区三区在线观看动漫| 国产在线久久久| 阿v免费在线观看| 99热免费精品在线观看| 制服丝袜中文字幕亚洲| 日本不卡一区| 97人人爽人人澡人人精品| 日韩成人一级大片| 亚洲片在线资源| 99在线免费视频观看| 日韩最新av| 天天做天天摸天天爽国产一区 | 国产午夜精品一区二区三区| 成年人黄色在线观看| 日本免费在线一区| 亚洲第一黄色| 你真棒插曲来救救我在线观看| 成av人片在线观看www| 欧美男男gaygay1069| 国产调教视频一区| 国产精品视频xxxx| 国产高清免费在线播放| 国产综合成人久久大片91| 欧美激情一区二区三区高清视频| 原千岁中文字幕| 国产日韩一区二区三区在线播放 | 色爱区综合激月婷婷| 亚洲国产精品www| 久久伊人精品| 欧美三片在线视频观看| 搞av.com| 久久久亚洲午夜电影| 国产精品免费在线| 亚洲综合av一区二区三区| 亚洲欧洲精品一区二区三区| 国产亚洲欧美一区二区三区| 日韩伦理一区二区| 高清欧美电影在线| 自拍视频在线网| 97精品国产97久久久久久久久久久久| 国产精品video| 在线看片福利| 亚洲综合一区在线| 韩日视频在线观看| 日本一区二区久久| 伊人天天久久大香线蕉av色| 久久中文字幕导航| 欧美精品一区二区三区很污很色的| 69免费视频| 成人精品一区二区三区四区 | 国产精品国产精品国产专区蜜臀ah | 国产午夜精品久久久久久免费视 | 日本一区二区三区国色天香 | 色视频www在线播放国产成人| 亚洲福利二区| 国产三区在线成人av| 久久白虎精品| 超碰97在线资源| 综合激情网...| 日韩欧美三级电影| 亚洲精品66| 国产伦精品免费视频| 人人精品久久| 亚洲综合在线播放| 日韩三区视频| 久久精品一区中文字幕| 久久最新网址| 先锋影音男人资源| 中文字幕一区二区三区精彩视频 | 黑粗硬长欧美在线视频免费的| 嫩草视频在线观看| 亚洲精品免费视频| 懂色av中文在线| 欧美黑人一区二区三区| 欧美一级黄色影院| 国产精品一区二区av日韩在线| av激情成人网| 日韩av大全| 亚洲第一综合色| 男人添女荫道口喷水视频| 精品少妇在线视频| 亚洲精品v亚洲精品v日韩精品| 97视频中文字幕| 神马香蕉久久| 深夜福利成人| 亚洲综合激情| 国产伦精品一区二区三区高清版| 9久草视频在线视频精品| 性做爰过程免费播放| 婷婷亚洲久悠悠色悠在线播放| 国产69精品久久久久9999人| 亚洲成av人影院在线观看| 秋霞a级毛片在线看| 欧美午夜在线观看| 日韩在线资源| 欧美日韩一级视频| 粉嫩久久久久久久极品| 久久精品亚洲热| 久久精品动漫| 亚洲一区三区在线观看| 精品一区二区成人精品| 亚洲欧美日韩精品综合在线观看| 天天做天天摸天天爽国产一区 | 亚洲小说欧美激情另类| 国产日本视频| 中文字幕亚洲激情| caoporn成人| 777精品视频| 中国av一区| 亚洲a成v人在线观看| 国产精品女同一区二区三区| av线上观看| 黑人巨大精品欧美一区二区一视频| 婷婷婷国产在线视频| 欧美丰满少妇xxxxx| 高清成人在线观看| 美女一区二区三区视频| 亚洲免费视频中文字幕| 香蕉网站在线| 国产精品视频一区二区高潮| 亚洲天堂av一区| 激情小说 在线视频| 国产精品扒开腿做爽爽爽视频 | 公共露出暴露狂另类av| 欧美一区二区三区视频免费播放| 97超碰在线公开在线看免费| 精品精品欲导航| 国产精品.xx视频.xxtv| 一区二区在线观| 日韩精品高清视频| 红杏视频成人| 国产三级三级看三级| 色八戒一区二区三区| 国产精品久久久久久久久久10秀 | 亚洲一区bb| 亚洲精品一区二区三区99| 日韩在线一区二区三区| 97蜜桃久久| 欧美这里只有精品| 精品少妇v888av| 好吊日精品视频| 日本免费成人网| 亚洲一区二区三区在线| 大色综合视频网站在线播放| 欧美精品在线一区| 91在线高清观看| 欧亚精品一区| 免费中文日韩| 成人欧美一区二区三区视频网页| 美女一区二区在线观看| 爽爽免费视频| 亚洲深夜福利在线| 懂色中文一区二区在线播放| 污片在线免费看| 欧美一区国产二区| 青青草原综合久久大伊人精品优势| aaaaaa亚洲| 91精品国模一区二区三区| 韩国av一区二区三区四区| 久久麻豆视频| 一级毛片免费观看| 久久香蕉综合色| 在线麻豆国产传媒1国产免费| 欧美专区在线观看| 91国产丝袜在线播放| 欧美hdxxxx| 久热爱精品视频线路一| 久久久综合色| www国产精品内射老熟女| 姬川优奈aav一区二区| 黄色免费成人| 三妻四妾完整版在线观看电视剧| 国产精品亚洲一区二区三区| 欧美性大战久久| 成人三级伦理片| 午夜精品毛片| 精品久久久久久中文字幕2017| 国产成人精品电影久久久| 韩国午夜理伦三级不卡影院| 91欧美日韩在线| 电影在线高清| 能在线观看的av| 日韩大片在线观看视频| 久久精品一二三| 亚洲黄页一区| 视频在线观看一区二区| av色综合久久天堂av综合| 亚洲性视频h| 日韩av网址大全| 一级毛片久久久|