【问题标题】:Initialize plain 2D array with a given function on compile time在编译时使用给定函数初始化普通二维数组
【发布时间】:2015-12-09 18:50:27
【问题描述】:

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

举个例子,假设一个函数f(x, y) = 10 * y + x,让x{1, 2, 3}中,y{4, 5, 6}中。我想创建一个包含内容的二维数组

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&lt;args1&gt;::over&lt;args2&gt;::value 中有两个参数包,args1args2,因此在其上应用... 同时扩展它们,我只有 3 个成员而不是 9 个。

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

我知道this answerthat answer。他们使用std::array而不是普通数组,所以他们首先构造一维数组,然后用多个一维数组初始化二维数组。但如果我理解正确的话,这个初始化必须在运行时完成。我想避免这种情况。但是,我对std::array 没有异议。我想通过适当的编译器,它们和普通数组一样快。

顺便说一句,这是我的possible solution 使用 C++14 中的通用constexpr 和一个关于它的问题。也欢迎任何关于如何使用 C++11 中的 constexpr 解决任务的想法。

【问题讨论】:

  • 先遍历行,再遍历列。
  • 我太可怕了,但现在写的方式是“模棱两可的”。该结构是嵌套的,但它没有嵌套的模板迭代。因此,也许可以尝试为顶级结构指定类型,然后使用可变参数列表创建另一个具有第二级严格的类型。然后用顶级实例化案例实例化一个特定案例。
  • 你真的需要二维数组吗?您刚刚找到了一维数组的解决方案
  • 澄清一下,如果您不嵌套模板级别,编译器将同时遍历行和列。但您想要的方式是,为每一行、每一列计算一个值。因此,对于每一行,指定一个列值数组。为行提供一个固定类型的实例化,并为列留下一个“开放的”可变参数列表。
  • @MrPisarik 同意。但这确实是一个好奇的问题。

标签: c++ arrays c++11 variadic-templates


【解决方案1】:

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

#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

Code in Compiler Explorer

【讨论】:

  • 感谢您的回答,但它仅适用于 C++14,不适用于 C++11,而我已经有了 C++14 的解决方案。
猜你喜欢
  • 2021-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2012-11-29
相关资源
最近更新 更多