我是一直使用C語言寫嵌入式程序的,最近看了一下STM32的觸摸屏輔助工具touchGFX,其輸出代碼是C++,感受到了 C++在模塊化代碼生成中的優勢。(我會陸續寫一些關於 C++的文件,主要結合touchGFX工具,從嵌入式的角度看 C++的學習應用)。
元操作的由來
今天講的元操作是基於類型的操作運算,而不是基於數值的運算,這點和普通程序代碼有很大不同。問題起始於1994年,Erwin Unruh在一次C++會議上展示了一段不能編譯的程序代碼,這可能是最著名的一段無法編譯的Erwin Unruh代碼。
<code>templatestruct D /<code>
{ D(void*); operator int(); };
templatestruct is_prime {
enum { prim = (p%i) && is_prime 2 ? p : 0), i -1> :: prim };
};
template < int i > struct Prime_print {
Prime_printa;
enum { prim = is_prime::prim };
void f() { D d = prim; }
};
struct is_prime<0,0> { enum {prim=1}; };
struct is_prime<0,1> { enum {prim=1}; };
struct Prime_print<2> { enum {prim = 1}; void f() { D<2> d = prim; } };
#ifndef LAST
#define LAST 10
#endif
main () {
Prime_print<last> a;
} /<last>
Erwin Unruh使用元操作編譯器,但是顯示這是無效 C++代碼。為什麼這段代碼如此著名,請看下面的編譯結果。
![C++元操作的由來和工作原理,程序Bug的意外收穫 #知識青年#](http://p2.ttnews.xyz/loading.gif)
編譯結果
請注意紅色部分代碼結構。 該程序在編譯的過程中,計算出了前30個質數。這意味著模版實例可以在編譯過程中完成計算,而且模版元操作是Turing-complete的(即狀態自動轉換),因此可以用於解決計算問題(當然,這裡也要考慮到遞歸計算的深度問題,在C++11裡至少可達到1024次遞歸計算)。
元操作工作原理
我們看一段階乘的運算代碼
<code>#include <iostream>
template// (2) /<iostream>/<code>
struct Factorial{
static int const value = N * Factorial::value;
};
template <> // (3)
struct Factorial<1>{
static int const value = 1;
};
int main(){
std::cout << std::endl;
std::cout << "Factorial<5>::value: " << Factorial<5>::value << std::endl; // (1)
std::cout << "Factorial<10>::value: " << Factorial<10>::value << std::endl;
std::cout << std::endl;
}
在(1)處調用 factorial<5>::value實現了對 (2)處模版的實例化,在初始化的過程中Factorial<4>::value也被實例化。這種遞歸一直運算直到 template Factorial<1> ,滿足 (3)處條件結束,看下圖
![C++元操作的由來和工作原理,程序Bug的意外收穫 #知識青年#](http://p2.ttnews.xyz/loading.gif)
遞歸過程
程序輸出結果
結果
那如何看到這結果是編譯時運算的呢?
上圖加深語句的反彙編代碼
可以看到,factorial<10>直接就是一個常數3628800賦值,因此可判斷是在編譯過程中計算出來的。
元操作雖然可以極大的提高程序運算效率,但是不建議大量使用,在嵌入式系統中適當的使用,卻能極大的提高系統運行效率。在touchGFX裡,使用到了typelist和元件操作,但是不是C++的庫文件,是touchGFX裡自定義的庫文件,可以進一步提高效率,縮減代碼。
謝謝關注,轉發。
閱讀更多 嵌入式經驗分享 的文章