【问题标题】:Using variadic templates to create a 2D array with variable column width?使用可变参数模板创建具有可变列宽的二维数组?
【发布时间】:2017-02-09 15:25:30
【问题描述】:

是否可以仅使用可变参数模板和 std::array 创建“稀疏”可变长度二维数组?稀疏是指每一行可以有可变数量的列。

理想情况下,我想实例化VariableLengthTable<int,2,4,3>() 之类的东西,并让它创建一个数组数组,这些数组将映射到{{0,1}, {0,1,2,3}, {0,1,2}} 之类的东西。我看过一些处理可变参数模板以创建多维数组的帖子,但它们都是对称的。

请注意,由于我正在使用内存非常受限的应用程序,因此我仅限于零成本抽象(例如 std::array)。

【问题讨论】:

  • 我不太确定你需要一个可变参数模板来做到这一点。 std::vector<std::vector<int>> 或至少 std::array<std::vector<int>,N> 不是一个选项吗?
  • 我正在寻找零成本或非常、非常低成本的产品。不幸的是,std::vector 对于我们的应用程序来说太大了。

标签: c++ arrays variadic-templates


【解决方案1】:

是的,原则上这应该是可能的。这里有一些帮助您入门:

template <class T, std::size_t... Dim>
using VariableLengthTable = std::tuple<std::array<T, Dim>...>;

这是std::arrays 的元组,每个元组的长度由模板参数之一指定。

请注意,因为 std::array 的长度是其类型的一部分,所以第一个维度不能是数组,因为它的成员需要不同的类型。但是,std::tuple 工作得很好。只要你愿意使用std::get&lt;i&gt;而不是[i],并且将自己限制在编译时is,你就可以了。

如果编译时i 不够用,您有两种选择:

一个,如上使用VariableLengthTable并添加运行时到编译时的转换。从概念上讲,类似switch:

T& get(std::size_t x, std::size_t y)
{
  switch (x) {
    case 0: return std::get<0>(varLenTable)[y];
    case 1: return std::get<1>(varLenTable)[y];
    case 2: return std::get<2>(varLenTable)[y];
    // and so on
  }
}

实际上,您可能需要使用递归或继承来组合它,以避免编译时越界访问。 Boost.Preprocessor 可能会对此有所帮助。

,将所有数据存储在一个顺序缓冲区中,并在运行时对其进行索引。像这样的:

template <class T, std::size_t... Dim>
class VariableLengthTable
{
  static const std::array<std::size_t, sizeof...(Dim)> dims = {{ Dim... }};

  static const std::array<std::size_t, sizeof...(Dim)> cumulDims = [](){
    std::array<std::size_t, sizeof...(Dim)> result;
    result[0] = 0;
    for (std::size_t idx = 1; idx < sizeof...(Dim); ++idx) {
      result[idx] = result[idx - 1] + dims[idx];
    }
    return result;
  }();

  std::array<T, cumulDims[sizeof...(Dim) - 1] + dims[sizeof...(Dim) - 1]> data;

public:
  T& get(std::size_t x, std::size_t y)
  {
    return data[cumulDims[x] + y];
  }
};

上面的代码是为了说明原理,不保证按原样编译。

【讨论】:

  • 谢谢,这可能正是我想要的。我对元组不是很熟悉。我试试看!
  • 经过进一步检查,由于std::tuple 对编译时is 的限制,我认为我不能在我的应用程序中使用它。这是一个很酷的解决方案,但不幸的是,它在运行时与数组数组的功能不同。我想我可以添加一个模板函数来访问get&lt;X&gt;(Y) 形式的单元格,但是在空间受限的应用程序中,这似乎并不理想。
  • @WilliamMoy 我添加了两种方法来支持运行时索引。
  • 感谢您的更新。 #2 似乎是我可能会尝试的路径。已回答!
猜你喜欢
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-08
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
相关资源
最近更新 更多