constexpr 關鍵字
C++11 引入了 constexpr
關鍵字,用於宣告可以在編譯時求值的函數或變數。 這樣的函數或變數可以在編譯時被求值,而不是在運行時,從而提高了程式的性能和效率。 constexpr
的使用時機通常是在需要在編譯時計算值的情況下,例如在模板元編程中、在宣告常數表達式時等。
簡單的來說,就是把執行時計算的時間移到 complie 時。
這麼好要不要全部 function 都改成 constexpr
? No !
不適合使用 constexpr
的一些例子
需要在運行時決定的情況: 如果變數的值需要在程式運行時才能確定,而不是在編譯時就能決定,那麼就不適合使用
constexpr
。比如從使用者輸入獲取的數值,或者需要從外部文件讀取的數值。依賴外部狀態的情況: 如果函數或變數的計算依賴於外部狀態的變化,而該外部狀態無法在編譯時獲取,那麼也不適合使用
constexpr
。例如需要訪問系統時間或文件系統狀態的情況。過於複雜的運算邏輯: 如果函數或變數的計算邏輯過於複雜,無法在編譯時完全展開和求值,那麼也不適合使用
constexpr
。constexpr
函數的計算在編譯時進行,如果計算邏輯過於複雜會增加編譯時間和編譯器的負擔。
驗證
以下我們特別來驗證 constexpr
增加編譯時間的部分。
計算的絕對時間不是重點,因為硬體等其他因素會造成每個電腦上編譯時間都不同, 但相對時間的差異,確實可以看出效果。
1
constexpr int result = fibonacci_constexpr(27);
其他三次分別為: 3.9, 3.8, 3.4 秒
1
int result = fibonacci_constexpr(27);
其他三次分別為: 1.8, 1.9, 1.8 秒
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
#include <iostream>
#include <chrono>
constexpr int fibonacci_constexpr(int n) {
return (n <= 1) ? n : fibonacci_constexpr(n - 1) + fibonacci_constexpr(n - 2);
}
int fibonacci(int n) {
return (n <= 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
auto start = std::chrono::high_resolution_clock::now();
// 在編譯時求值
constexpr int result = fibonacci_constexpr(27);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> duration = end - start;
std::cout << "Calculate at compile time: " << std::endl;
std::cout << "time: " << duration.count() << " (s)" << std::endl;
std::cout << "-----------------" << std::endl;
start = std::chrono::high_resolution_clock::now();
// 在 runtime 時求值
int result2 = fibonacci(27);
end = std::chrono::high_resolution_clock::now();
duration = end - start;
std::cout << "Calculate at run time: " << std::endl;
std::cout << "time: " << duration.count() << " (s)" << std::endl;
return 0;
}
結果
執行時計算時間,而 fibonacci_constexpr(27)
在 compile 時已經計算完畢,在執行時只是一個常數被帶入。 因此執行速度很快。 反之,fibonacci
在 runtime 時才去計算,可以從計算時間看出巨大的差異。
應該很清楚了吧,哈 !