在编译时创建查找表

9

我是C++的新手。如果有一个constexpr f,在编译时最简单的方式是什么,以创建数组{f(0), f(1), ..., f(1023)}?


1
不确定你使用的是哪个编译器/ C++标准,但是这个链接似乎可以解决问题? - Borgleader
3个回答

8

您可以使用立即调用的lambda表达式:

#include <array>

using ResultT = int;
constexpr ResultT f(int i)
{
    return i * 2;
}

constexpr auto LUT = []
{
    constexpr auto LUT_Size = 1024;
    std::array<ResultT, LUT_Size> arr = {};

    for (int i = 0; i < LUT_Size; ++i)
    {
        arr[i] = f(i);
    }

    return arr;
}();

static_assert(LUT[100] == 200);

我一直很惊讶 <algorithm> 没有类似于 std::generate_n 的函数模板,可以将索引传递给生成器。生成器不应该携带自己的状态。 - Adrian McCarthy

5

DeviationN的解决方案需要使用C++17(用于constexpr lambda)。

作为补充,这里提供了一个使用C++14的解决方案。

#include <array>

constexpr int f(int i) { return 2 * i; }

template <std::size_t... I>
constexpr auto lookup_helper(std::index_sequence<I...>)
{
  return std::array<int, sizeof...(I)>({f(I)...});
}

template <size_t N>
constexpr auto lookup()
{
  return lookup_helper(std::make_index_sequence<N>());
}

int main()
{
  constexpr int N = 10;
  constexpr auto a = lookup<N>();

  // Check it works
  static_assert(a[N-1]==2*(N-1));
}

这个想法是使用std::index_sequence<I...>。但是如果您可以使用C++17,DeviationN的解决方案更加便利。


5

对于一次性需求,Lambda 解决方案很好。如果需要多次使用,可以使用类似如下的 constexpr 函数模板进行泛化:

#include <algorithm>
#include <array>
#include <cstdint>

template <typename T, std::size_t N, typename Generator>
constexpr std::array<T, N> make_array(Generator fn) {
    std::array<T, N> table = {};
    for (std::size_t i = 0; i != N; ++i) {
        table[i] = fn(i);
    }
    return table;
}

然后,您可以使用它来创建编译时查找表:

constexpr float doubler(std::size_t i) { return 2.0f * i; }

constexpr auto lookup_table = make_array<float, 5>(doubler);
static_assert(lookup_table[3] == 6.0f);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接