2017-07-24 31 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