2013-02-23 21 views
0

據我所知,正常的C++代碼在編譯時轉換爲彙編程序,然後由CPU在運行時執行。所以我不太明白模板元編程的好處是什麼?C++模板Metaprogramming-不知道我挺煩惱嗎?

維基百科說,有關模板元編程如下:

模板元編程是由編譯器與其他地區合併一元編程技術,其中 模板用於由編譯器生成的臨時源代碼, 然後編譯源代碼和 。這些模板的輸出包括編譯時間 常量,數據結構和完整功能。使用 模板可以被認爲是編譯時執行。

這似乎並沒有強調模板元編程對我的優點......?

我在問,因爲我感興趣的是模板元編程可以用來優化/提高低延遲C++應用程序的效率。我可能一路上都沒有正確理解,所以請隨時糾正我的理解。

+4

直到需要時纔會理解。 – 2013-02-23 20:13:28

+0

@SethCarnegie你有沒有例子證明它非常有用? – user997112 2013-02-23 20:27:05

+0

@ user997112矩陣乘法是一種應用程序,其中使用模板元編程可避免涉及矩陣運算的複雜表達式中的許多昂貴的臨時對象。 – juanchopanza 2013-02-23 20:32:22

回答

3

您是否閱讀過那些完全討論TM的文章?例如:

看着模板元編程的(1種),一個簡單的方法是 「強」 的memoization 。一個常見的例子如下:

假設你的程序需要計算某個數字的因子。使用TM,您可以在編譯時計算階乘,這會增加編譯時間(和二進制大小),但會降低運行時間。示例代碼來自上面的第二個站點;如果你這樣做了「天真」的方式,你必須代碼看起來像:

int factorial(int n) { 
    return (n==0) ? 1 : n*factorial(n-1)l 
} 

int main() { 
    cout << factorial(5) << endl; 
    return 0; 
} 

隨着以舊換新,我們可以計算在編譯時的階乘:

// factorial.cpp 

#include <iostream> 

template <int N> 
struct Factorial { 
    enum { value = N * Factorial<N-1>::value }; 
}; 

template <> 
struct Factorial<1> { 
    enum { value = 1 }; 
}; 

// example use 
int main() { 
    const int fact5 = Factorial<15>::value; 
    std::cout << fact5 << endl; 
    return 0; 
} 

這裏Factorial<15>::value本質一個編譯時常量。與往常一樣,簡單化的例子並不是特別有用,但希望你能得到它的要點。

+0

好的,但事實確實如此,只有當我在運行時執行時總想知道階乘15纔有用?我很欣賞這是一個簡單的例子 - 但是(例子是解釋TMP的常見例子),如果我有一個帶有因子按鈕的計算器,我可以剛剛聲明一個const int,然後用我的計算器來獲得他的價值,比寫所有的代碼? – user997112 2013-02-23 20:28:59

+0

你是對的; TM常常用於:生成編譯時查找表。儘管這可能看起來微不足道,但像crc32和md5這些聰明的TM實現(利用類似構造的查找表)顯着提高了散列性能。考慮一個計算,並不像在你的計算器上做'5!'那麼簡單。 – 2013-02-23 20:33:27

+2

@ user997112所以每次你需要一個新的因子,你會得到你的計算器,計算出數字,輸入到你的程序中,而不是編寫「因子 :: value」? – juanchopanza 2013-02-23 20:34:30

0

另一個例子是如何計算斐波納契數列。

普通遞歸的方式做到這一點:

uint64_t fibonacci(int n) { 
    if (n <= 2) 
     return 1; 
    else 
     return fibonacci(n - 1) + fibonacci(n - 2); 
} 

使用元編程:

template< int n > struct Fibonacci { 
    static const uint64_t value = Fibonacci< n-1 >::value + Fibonacci< n-2 >::value; 
}; 

template<> struct Fibonacci<1> { 
    static const uint64_t value = 1; 
}; 

template<> struct Fibonacci<0> { 
    static const uint64_t value = 0; 
}; 

現在,你可以自己嘗試致電fibonacci(80)Fibonacci<80>::value。遞歸函數可能無法正常工作和崩潰,使用元編程的函數將會非常好並且非常快。

+0

編譯器如何避免大的遞歸(沒有尾遞歸)? – Sebastian 2013-02-24 12:53:56