在编译时用给定的函数初始化普通2D数组

Initialize plain 2D array with a given function on compile time

本文关键字:初始化 2D 数组 函数 编译      更新时间:2023-10-16

我想创建一个由一些已知函数填充的2D数组,该函数没有运行时开销。

举个例子,假设函数f(x, y) = 10 * y + x,让x{1, 2, 3}中,y{4, 5, 6}中。我想创建一个具有内容的2D阵列

41 42 43
51 52 53
61 62 63

现在,最简单的方法就是直接在我的源代码中对值进行硬编码。它确实适合我的任务,所以这个问题只是出于好奇。

我想创建一个metafunc和一个具有某种黑魔法的结构,这使我能够定义xy的给定值集的数组。像这样:

template<int X> struct Func {
  template<int Y> struct over {
    static const int value = 10 * Y + X;  // f(x, y)
  };
};
template<int... args1> struct Rows {
  template<int... args2> struct Cols {
    static const int data[sizeof...(args1)][sizeof...(args2)];
  };
};
template<int... args1>
template<int... args2>
const int Rows<args1...>::Cols<args2...>::data[sizeof...(args1)][sizeof...(args2)] = {
  { Func<args1>::over<args2>::value... }  // This does not do what I want :(
                                          // Need some black magic here
};
// Here is my precious table
const auto& table = Rows<1, 2, 3>::Cols<4, 5, 6>::data;

如果我打印表中的值,我会得到这个:

41 52 63
 0  0  0
 0  0  0

我知道发生了什么,术语Func<args1>::over<args2>::value中有两个参数包,args1args2,所以在它上面应用...可以同时扩展它们,我只有3个成员,而不是9个。

如果你已经走到了这一步,你就已经明白我想要什么了。所以问题是,我该怎么做?如何将省略号分别应用于两个参数包,以便在初始值设定项中使用笛卡尔组合?或者也许还有其他方法可以做到这一点?

我知道这个答案和那个答案。他们使用std::array而不是普通阵列,因此他们首先构造1D阵列,然后用许多1D阵列初始化2D阵列。但如果我理解正确的话,这个初始化必须在运行时中完成。我想避免这种情况。但是,我不反对std::array。我想,使用适当的编译器,它们的速度和普通数组一样快。

顺便说一句,这是我使用C++14中的广义constexpr的可能解和一个问题。关于如何使用C++11中的constexpr来解决任务的任何想法也受到欢迎。

我找到它的唯一方法是用逗号分隔参数包并展开其中一个,然后从外部展开另一个:

#include <array>
#include <utility>
using namespace std;
template<class T, T Y, T... Xs>
constexpr array<T, sizeof...(Xs)> a1{10*Y+Xs...};
template<class T, T... Xs, T... Ys>
constexpr auto a2(integer_sequence<T, Xs...>, integer_sequence<T, Ys...>) {
    return array<array<T, sizeof...(Xs)>, sizeof...(Ys)>{a1<T, Ys, Xs...>...};
}
array<array<int, 3>, 3> table(a2(
    integer_sequence<int, 1, 2, 3>(),
    integer_sequence<int, 4, 5, 6>()
));

asm的结果是:

table:
        .long   41
        .long   42
        .long   43
        .long   51
        .long   52
        .long   53
        .long   61
        .long   62
        .long   63

编译器资源管理器中的代码