2017-07-24 98 views
10

表下面是應該產生2048元的餘弦查找表,由昌邑顧從圖書大廈嵌入式系統採取的一個片段:餘弦查找與C++

#include <cmath> 
#include <array> 

template<typename T> 
constexpr T look_up_table_elem (int i) { 
    return {}; 
} 

template<> 
constexpr uint16_t look_up_table_elem (int i) { 
    return round (cos (static_cast <long double>(i)/2048 * 3.14159/4) * 32767); 
} 


template<typename T, int... N> 
struct lookup_table_expand{}; 

template<typename T, int... N> 
struct lookup_table_expand<T, 1, N...> { 
    static constexpr std::array<T, sizeof...(N) + 1> values = {{ look_up_table_elem<T>(0), N... }}; 
}; 

template<typename T, int L, int... N> 
struct lookup_table_expand<T, L, N...>: lookup_table_expand<T, L-1, look_up_table_elem<T>(L-1), N...> {}; 


template<typename T, int... N> 
constexpr std::array<T, sizeof...(N) + 1> lookup_table_expand<T, 1, N...>::values; 

const std::array<uint16_t, 2048> lookup_table = lookup_table_expand<uint16_t, 2048>::values; 

注:寫於C++ 11。

我來自一個主要的Java世界,我對C++的基本知識有了一個很好的把握。因爲它從來沒有真正在書中解釋說,我是爲這如何片斷實現任務真的很困惑,以及它是如何實現以下(也考慮出書):

模板專業化和類繼承將幫助我們擺脫constexpr函數只能將返回狀態作爲其函數體的限制,這就是爲什麼當表大小增加時必須手動填充查找表的原因。

任何幫助將不勝感激。我理解帶有constexpr模板的部分會產生實際值,但我真的不確定結構在做什麼以及最終數組是如何構建的。

回答

8

對於首先讓我們來看看到下面一行:

const std::array<uint16_t, 2048> lookup_table = 
     lookup_table_expand<uint16_t, 2048>::values; 

那裏lookup_table將從lookup_table_expand<uint16_t, 2048>結構內舉行values陣列拷貝構造。這很簡單,現在讓我們看看模板實例化完成後會發生什麼。

我們與空體(其中向前聲明就足夠了,我們不會以這種形式使用)的主模板:

template<typename T, int... N> 
struct lookup_table_expand { 
}; 

lookup_table_expand<uint16_t, 2048>將匹配主模板以下partial specialization

template<typename T, int L, int... N> 
struct lookup_table_expand<T, L, N...> : 
     lookup_table_expand<T, L - 1, look_up_table_elem<T>(L - 1), N...> { 
}; 

由於模板上方將與生長模板parameter list直到當前模板遞歸地實例化的繼承將不匹配於主TEM的下面部分特板:

template<typename T, int... N> 
struct lookup_table_expand<T, 1, N...> { 
    static constexpr std::array<T, sizeof...(N) + 1> values = {{ 
     look_up_table_elem<T>(0), N... 
    }}; 
}; 

的匹配上面的模板會時L在遞歸變得1發生。此時模板參數列表(N...)將包含值下面的函數的調用的結果從1到2047:

constexpr uint16_t look_up_table_elem(int i) { 
    return round(cos(static_cast<long double>(i)/2048 * 3.14159/4) * 32767); 
} 

這是lookup_table_expand模板(values)的唯一成員將與初始化模板參數列表的值。

注意values是可在class/struct聲明被初始化一個static constexpr數據成員,因此下面的行甚至沒有必要:

template<typename T, int... N> 
constexpr std::array<T, sizeof...(N) + 1> lookup_table_expand<T, 1, N...>::values; 

values陣列將由lookup_table_expand<uint16_t, 2048>被繼承,所以在最後您可以從該結構訪問它。

+1

很好的解釋,讓事情變得更清晰! – Nirri