c++ - C++余弦查找表

标签 c++ c++11 templates lookup-tables

这是一个应该生成 2048 个元素的余弦查找表的片段,摘自顾长义的《构建嵌入式系统》一书:

#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++ 的基础知识有一定的了解。由于书中从未真正解释过,我真的很困惑这段代码是如何完成任务的,以及它是如何实现以下内容的(也从书中取出):

Template specialization and class inheritance will help us get rid of the restriction that constexpr function can only have return state as its function body, which is why the lookup table has to be manually populated when the table size increases.

如有任何帮助,我们将不胜感激。我理解带有 constexpr 模板的部分会生成实际值,但我真的不确定结构在做什么以及最终数组是如何构造的。

最佳答案

首先让我们看一下下面一行:

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 ) 将使用模板参数列表的值进行初始化。

请注意 valuesstatic 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> 继承, 所以最后你可以从那个结构访问它。

关于c++ - C++余弦查找表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45282276/

相关文章:

c++ - 我需要检查是否从 operator=? 抛出异常?

c++ - 每个基类的预写主函数

c++ - "sizeof"在此帮助程序中如何确定数组大小?

c++ - 强制执行显式默认的特殊成员函数生成

css - 当建议的结果显示在我们的搜索框中时,我们无法点击到建议的产品 sku;我们该如何解决这个问题?

c++ - 在 cmake : Linux 中使用 CPack 生成两个不同的包

c++ - 使用枚举实例化模板

c++ - .c编程如何在客户端和服务器之间建立sip session

c++ - 寻找增长函数

c++ - 如何在重用 std::stringstream 变量时避免使用 std::stringstream.str() 和 std::stringstream.clear() ?