可以从可变参数模板填充多维数组吗?

时间:2013-12-02 17:30:10

标签: c++11 multidimensional-array variadic-templates

所以我有类似的东西:

template<unsigned int W,unsigned int H>
class Class
{
    int data[W][H];
    Class(const (&_data)[W][H])
    {
        for (int x=0;x<W;x++)
            for (int y=0;y<H;y++)
                data[x][y] = _data[x][y];
    }
    template<class... args>
    Class()
    {
        /// black magic
    }
}

我能替换“黑魔法”,所以第二个构造函数会接受W * H整数? 例如:

Class<3,2> class1(1,2,3,4,5,6);

4 个答案:

答案 0 :(得分:2)

首先,您的示例中存在一些语法错误,因为在类声明之后缺少分号并且构造函数是私有的。

除此之外,如果您想将数字存储在row-major order中,那么您应该将矩阵/ 2d数组声明为int data[H][W](高度优先,然后是宽度)。

要存储可变参数包中的值,您只需在容器的内部展开它们即可。 std::array,并使用列表初始化

template <typename... Args>
Class(Args&&... args) {
    const std::array<int, H * W> temp{std::forward<Args>(args)...};
    /* ... */
};

我还使用universal references并完美转发以保留包的引用类型。

要填充二维数组,您只需迭代temp中的所有元素并将它们存储在成员数组中。

for (std::size_t h = 0; h != H; ++h)
    for (std::size_t w = 0; w != W; ++w)
        data[h][w] = temp[h * W + w];

See a full example here

答案 1 :(得分:2)

这有效:

#include <array>
#include <utility>
#include <iostream>

template<unsigned W,unsigned H>
struct Foo
{
  std::array<std::array<int, H>, W> data;
  template<typename... Args>
  Foo(Args&&... args):
    data{ std::forward<Args>(args)... }
  {}
};
int main()
{
  Foo<2,2> x(1,2,3,4);
  for( auto&& a : x.data ) {
    for( unsigned z : a ) {
      std::cout << z << ",";
    }
  std::cout << "\n";
}

但是会在内部array中公开存储顺序。

std::array是一个围绕原始C数组的语法糖。

答案 2 :(得分:2)

有一些替代答案可能更实用,更易于实现,但我将展示如何使用编译时for循环实现这一目的,以展示黑魔法。

这是一个编译时for循环。

/* Compile-time for-loop up to N. */
template <std::size_t N>
struct For {

  /* Call f<I>(args...) N times. */
  template <typename F, typename... Args>
  void operator()(F &&f, Args &&... args) const {
    Impl<0, N>()(std::forward<F>(f), std::forward<Args>(args)...);
  }

  private:

  /* Forward declaration. */
  template <std::size_t I, std::size_t End>
  struct Impl;

  /* Base case. Do nothing. */
  template <std::size_t End>
  struct Impl<End, End> {

    template <typename F, typename... Args>
    void operator()(F &&, Args &&...) const { /* Do nothing. */ }

  };  // Impl<End, End>

  /* Recursive case. Call f<I>(args...), then recurse into next step. */
  template <std::size_t I, std::size_t End>
  struct Impl {

    template <typename F, typename... Args>
    void operator()(F &&f, Args &&... args) const {
      std::forward<F>(f).template operator()<I>(std::forward<Args>(args)...);
      Impl<I + 1, End>()(std::forward<F>(f), std::forward<Args>(args)...);
    }

  };  // Impl<I, End>

};  // For<N>

这是一个简单的用例。

struct Print {

  template <std::size_t I>
  void operator()(int x, int y) const {
    std::cout << "Iteration " << I << ": " << x << ' ' << y << std::endl;
  }

};  // Print

For<3>()(Print(), 1, 2);

输出

Iteration 0: 1 2
Iteration 1: 1 2
Iteration 2: 1 2

现在有了这个,我们就可以嵌入这个编译时for循环,就像我们如何嵌套运行时for循环一样。这是使用此For&lt;&gt;的Matrix类。模板。

/* Defines an M by N Matrix, (Row by Col). */
template <std::size_t M, std::size_t N>
class Matrix {
  public:

  /* Our underlying M by N matrix. */
  using Data = std::array<std::array<int, N>, M>;

  /* Construct off of M * N arguments. */
  template <typename... Args>
  Matrix(Args &&... args) {
    static_assert(sizeof...(Args) == M * N,
                  "The number of arguments provided must be M * N.");
    ForEach(AssignImpl(),
            data_,
            std::forward_as_tuple(std::forward<Args>(args)...));
  }

  /* Print each element out to std::cout. */
  void Write(std::ostream &strm) const {
    ForEach(WriteImpl(), strm, data_);
  }

  private:

  /* Our outer for loop. Call InnerFor() M times.
     Resembles: 'for (std::size_t i = 0 ; i < M; ++i) {' */
  template <typename F, typename... Args>
  void ForEach(F &&f, Args &&... args) const {
    For<M>()(InnerFor(), std::forward<F>(f), std::forward<Args>(args)...);
  }

  /* Our inner for loop. Call ForBody() N times.
     Resembles: 'for (std::size_t j = 0; j < N; ++j) {' */
  struct InnerFor {

    template <std::size_t I, typename F, typename... Args>
    void operator()(F &&f, Args &&... args) const {
      For<N>()(ForBody<I>(),
               std::forward<F>(f),
               std::forward<Args>(args)...);
    }

  };  // InnerFor

  /* The body of our for loop. Call f<I, J>(args...); */
  template <std::size_t I>
  struct ForBody {

    template <std::size_t J, typename F, typename... Args>
    void operator()(F &&f, Args &&... args) const {
      std::forward<F>(f)
          .template operator()<I, J>(std::forward<Args>(args)...);
    }

  };  // ForBody<I>

  /* Given the M by N array and a tuple of length M * N, assign the array. */
  struct AssignImpl {

    template <std::size_t I, std::size_t J, typename Arg>
    void operator()(Data &data, Arg &&arg) const {
      data[I][J] = std::get<I * N + J>(std::forward<Arg>(arg));
    }

  };  // AssignImpl

  /* Given an output stream and our data, print the data at (I, J). */
  struct WriteImpl {

    template <std::size_t I, std::size_t J>
    void operator()(std::ostream &strm, const Data &data) const {
      strm << data[I][J] << std::endl;
    }

  };  // WriteImpl

  /* Our underlying M by N array. */
  Data data_;

};  // Matrix

以下是std::cout的构建和写作的快速演示。

int main() {
  Matrix<3, 2> matrix{101, 102,
                      201, 202,
                      301, 302};
  matrix.Write(std::cout);
}

答案 3 :(得分:0)

您可以使用std::initializer_list作为构造函数参数,因为您的数组只有int[][]类型。

Class(std::initializer_list<int> il)
{
    if(il.size() < W*H)
        throw string("Insufficient elements");//if lesser no. of elements are given.
    auto it = il.begin();// iterator to the first element of the list.
    for(int i =0;i< W;++i)
    {
        for(int j =0; j < H;++j)
        {
            data[i][j] = *it++;// increment the iterator
        }
    }
}

呼叫网站将如下所示:

Class<3,2> c{1,2,3,4,5,6};

Class<3,2> c = {1,2,3,4,5,6};

如果给出更多元素,则丢弃额外的元素。 initializer_list可以提供类型安全性,如果找到缩小范围,将为您提供诊断。