我一直在尝试实现编译器生成的查找表包含正弦函数的值。C++代码看起来像这个
#include <cstdlib>
#include <cmath>
#include <array>
#include <iostream>
using namespace std;
template<typename T>
constexpr T look_up_table_elem(int i)
{
return {};
}
template<>
constexpr float look_up_table_elem(int i)
{
return sin(static_cast<float>(i)*2*3.14/64);
}
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<float, 65> lookup_table = lookup_table_expand<float, 65>::values;
int main(int argc, char** argv) {
for(const float &item : lookup_table){
std::cout << "Sin: " << item << std::endl;
}
return 0;
}
我一直在为汇编过程而苦恼。
main.cpp: In instantiation of 'struct lookup_table_expand<float, 65>':
main.cpp:49:74: required from here
main.cpp:44:52: error: conversion from 'float' to 'int' in a converted constant expression
44 | : lookup_table_expand<T, L-1, look_up_table_elem<T>(L-1), N...> {};
| ~~~~~~~~~~~~~~~~~~~~~^~~~~
main.cpp:44:52: error: could not convert 'look_up_table_elem<float>((65 - 1))' from 'float' to 'int'
main.cpp:49:76: error: 'values' is not a member of 'lookup_table_expand<float, 65>'
49 | const std::array<float, 65> lookup_table = lookup_table_expand<float, 65>::values;
| ^~~~~~
有人能告诉我我做错了什么吗?
代码可以大大简化以生成LUT:
template <std::size_t N, typename F = std::identity>
constexpr auto gen_float_array(const F& f = F{})
{
std::array<float, N> arr;
for (std::size_t i = 0; i < N; ++i)
arr[i] = f(static_cast<float>(i));
return arr;
}
它可以如下使用:
constexpr auto lookup_map =
gen_float_array<32>([](auto f) {
return f * 3.14f; // here could a call be placed to a constexpr sin function
});
示例:https://godbolt.org/z/ssEhK6bd7
正如Markus Mayr所指出的,您仍然需要一个constexpr
sin函数来获得您的用例所需的结果。
我真的不明白你想在这里做什么,但错误消息表明look_up_table_elem
返回一个浮点值,并且你正在将它输入到int ...
参数包中,如下所示:
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...> {};
顺便说一句,这就是我将如何实现这样的功能:
constexpr float lookup_table_elem(std::size_t i, std::size_t n)
{
return static_cast<float>(i) / static_cast<float>(n); // Have a constexpr sin function here!
}
template <class T>
struct lookup_table_impl;
template <std::size_t... I>
struct lookup_table_impl<std::index_sequence<I...>>
{
static constexpr std::size_t N = sizeof...(I);
static constexpr std::array<float, N> values{ lookup_table_elem(I, N) ... };
};
template <std::size_t N>
using lookup_table = lookup_table_impl<std::make_index_sequence<N>>;
template <std::size_t N>
constexpr auto lookup_table_values = lookup_table<N>::values;
请注意,std::sin
不是constexpr函数(还不是?(。您必须在这里编写自己的编译时近似值。
正如@HolyBlackCat在下面的一条评论中所建议的那样,以下非常简单的解决方案在现代C++中也是可能的(我认为>=17(:
template <std::size_t N>
constexpr std::array<float, N> make_lookup_table()
{
std::array<float, N> v;
for (std::size_t i = 0u; i < N; ++i)
{
v[i] = static_cast<float>(i); // Insert constexpr sin function here!
}
return v;
}
template <std::size_t N>
constexpr auto lookup_table_values = make_lookup_table<N>();