【问题标题】:How to efficiently fill a 2D std::array with enum如何用枚举有效地填充 2D std::array
【发布时间】:2017-05-12 02:12:23
【问题描述】:

我正在尝试找到一种有效且正确的方法来用 enum 值填充 2D std::array 矩阵。我正在这样做:

#include <iostream>
#include <array>

template<class T, size_t ROW, size_t COL>
using Matrix = std::array<std::array<T, COL>, ROW>;

enum class State { FREE = 0, BUSY, BLOCKED, RESERVED };

int main() {
  const int mapX = 4;
  const int mapY = 9;

  // create a 5x10 2D array
  Matrix<State, mapY, mapX> MapMatrix;

  // fill array with State::RESERVED value
  for (int y = 0; y <= mapY; y++) MapMatrix[y].fill(State::RESERVED);

  std::cout << "MapMatrix contains:\n";

  for (int y = 0; y <= mapY; ++y) {
    for (int x = 0; x <= mapX; ++x) {
      std::cout << static_cast<int>(MapMatrix[x][y]) << " ";
    }
    std::cout << std::endl;
  }

  return 0;
}

for 循环我正在做用enum 值填充矩阵的最佳方法吗?有没有办法在Matrix&lt;State, mapY, mapX&gt; MapMatrix的声明期间填充矩阵(像构造函数一样)?

谢谢!

【问题讨论】:

    标签: c++ arrays enums c++14 stdarray


    【解决方案1】:

    除非你用零填充它,或者你明确指定每个元素,否则你不能在初始化时填充它。如果你重新排列你的枚举使RESERVED 为零,那么你可以像这样初始化它:

    Matrix<State, mapY, mapX> MapMatrix = {};
    

    如果你不能这样做,那么是的,for 循环可能是最好的选择。把事情简单化。但是你有几个问题。首先,您的评论说您正在创建一个 5x10 数组,但您不是。您正在创建一个 4x9 数组。如果要创建 5x10 数组,则需要传递 5 和 10 作为模板参数。我认为您可能对大小为 N 的数组的最后一个元素是 N - 1 这一事实感到困惑。这个不相干的问题仅与访问数组的元素有关,与指定数组的大小无关数组。

    其次,您正在遍历数组的末尾,因为您的循环条件是y &lt;= mapY,而不是y &lt; mapY。但如果你只使用 range-for 循环会更好。

    for (auto& arr : MapMatrix)
        arr.fill(State::RESERVED);
    

    【讨论】:

    • 感谢您的快速回答。是的,我通过包含“从 0 开始”索引来计算 5x10。此外,刚刚测试了您的 range-for 循环,效果很好。我无法更改 RESERVED 的值,但使用 range-for 循环并不是什么大问题。我虽然可能是我想多了。
    【解决方案2】:

    我认为基于循环的初始化是一个很好的解决方案。

    但是,只是为了好玩,我建议您另一种解决方案std::index_sequence 和基于模板包扩展。

    一个工作示例(已修正索引)

    #include <iostream>
    #include <utility>
    #include <array>
    
    template <typename T, std::size_t ROW, std::size_t COL>
    using Matrix = std::array<std::array<T, COL>, ROW>;
    
    enum class State { FREE = 0, BUSY, BLOCKED, RESERVED };
    
    template <typename T, std::size_t ... Rs, std::size_t ... Cl>
    Matrix<T, sizeof...(Rs), sizeof...(Cl)> initMat
       (T                          const & tVal,
        std::index_sequence<Rs...> const &,
        std::index_sequence<Cl...> const &)
     {
       auto col = std::array<T, sizeof...(Cl)>{ { ((void)Cl, tVal)... } };
    
       return Matrix<T, sizeof...(Rs), sizeof...(Cl)>
        { { ((void)Rs, col)... } };
     }
    
    int main()
     {
       constexpr std::size_t mapX =  5U;
       constexpr std::size_t mapY = 10U;
    
       // create a 5x10 2D array
       auto MapMatrix = initMat(State::RESERVED,
                                std::make_index_sequence<mapX>(),
                                std::make_index_sequence<mapY>());
    
       std::cout << "MapMatrix contains:\n";
    
       for ( auto y = 0U ; y < mapY ; ++y )
        {
          for ( auto x = 0U ; x < mapX ; ++x )
             std::cout << static_cast<int>(MapMatrix[x][y]) << " ";
    
          std::cout << std::endl;
        }
    
       return 0;
     }
    

    【讨论】:

    • 我真的很喜欢你的解决方案,很好的例子!它还使代码在开始索引方面不那么混乱。当我今晚回来时,我将对大型地图初始化进行 chrono::duration 测试,并与 range-for 循环填充进行比较。谢谢!
    • 如果我做一个 500x100 的数组,你的方法在我的计算机上需要 0.182116 毫秒来填充数组,而 range-for 循环需要 0.388968 毫秒,这是一个很大的性能提升!如果我能获得非常大的数字(10000x10000),那么基准测试会更容易,但那时我会得到 SEGFAULTS ......再次感谢!
    • @Simog - 计算std::array 将数据放入堆栈;因此,对于大量数字,您应该使用std::vector(或其他基于堆的容器)或通过智能指针使用std::array
    • 是的,当我搜索问题时,我认为这是堆栈大小。无论如何,我真的不需要那么大的应用程序,只是想要一些更好的数字来比较。谢谢!
    猜你喜欢
    • 2021-07-27
    • 1970-01-01
    • 2021-05-31
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多