这是一个片段,应该生成2048个元素的余弦查找表,取自Changyi Gu的“Building Embedded Systems”一书:
#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模板生成实际值的部分,但我真的不确定结构正在做什么以及如何构造最终数组。
答案 0 :(得分:8)
首先让我们来看看以下一行:
const std::array<uint16_t, 2048> lookup_table =
lookup_table_expand<uint16_t, 2048>::values;
lookup_table
将从values
结构中保存的lookup_table_expand<uint16_t, 2048>
数组进行复制构造。这很简单,现在让我们看看模板实例化完成后会发生什么。
我们有一个空主体的主模板(前向声明就足够了,我们不会在这种形式下使用它):
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进行递归实例化,直到当前模板与主模板的以下部分特化不匹配为止:
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
是static constexpr
数据成员,可以在class
/ struct
声明中进行初始化,因此以下行甚至不需要:
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>
继承,因此最后您可以从该结构中访问它。