2017-05-12 7 views
2

enum 값을 사용하여 2D std::array 행렬을 채우는 효율적이고 적절한 방법을 찾으려고합니다. 나는이 일을하고있다 :효율적으로 2D std :: array를 enum으로 채우는 방법

#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; 
} 

루프에 대한 나는 enum 값 행렬을 채울 수있는 가장 좋은 방법 일을하고 있습니까? Matrix<State, mapY, mapX> MapMatrix (생성자와 같은) 선언 중에 행렬을 채울 방법이 있습니까?

감사합니다!

답변

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; 
} 
+0

나는 당신의 해결책, 훌륭한 본보기를 정말 좋아합니다! 또한 인덱스 시작과 관련하여 코드의 혼동을 덜어줍니다. 오늘 밤에 돌아 오면 큰지도 초기화에 대해 _chrono :: duration_ test를 수행하고 range-for 루프 채우기와 비교합니다. 감사! – Simog

+0

500x100 배열을 수행하는 경우 배열에 채우기 위해 내 컴퓨터에서 0.182116ms가 소요되지만 range-for 루프는 0.388968ms가 걸립니다. 성능이 크게 향상됩니다! 매우 큰 숫자 (10000x10000)로 들어갈 수 있다면 벤치 마크하기가 더 쉬웠 겠지만 그 순간에 나는 분열합니다 ... 다시 한번 감사드립니다! – Simog

+0

@Simog -'std :: array'는 스택에 데이터를 넣는다. 그래서 많은 수의 경우 스마트 포인터를 통해'std :: vector' (또는 다른 힙 기반 컨테이너) 또는'std :: array'를 사용해야합니다. – max66

3

0으로 채우지 않거나 모든 요소를 ​​명시 적으로 지정하지 않으면 초기화시 채울 수 없습니다. 당신이 당신의 열거를 재 배열하면 RESERVED가 0이, 당신은 다음과 같이 초기화 할 수 있도록 : 당신이 할 수없는 경우

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

는 다음 네, for 루프는 아마도 최선의 방법입니다. 단순하게 유지하십시오. 하지만 몇 가지 문제가 있습니다. 첫째, 귀하의 의견에 따르면 5x10 배열을 만들고 있지만 그렇지 않습니다. 4x9 배열을 만들고 있습니다. 5x10 배열을 만들려면 템플릿 매개 변수로 5와 10을 전달해야합니다. 크기가 N 인 배열의 마지막 요소가 N - 1이라는 사실에 대해 혼란 스러울 것 같아요.이 by-by-one 문제는 배열의 요소를 액세스 할 때만 관련이 있습니다. 정렬.

두 번째로 루프 상태가 y < mapY이 아닌 y <= mapY이기 때문에 배열 끝을 반복하고 있습니다. 그러나 range-for 루프를 사용했다면 더 좋을 것입니다.

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

감사합니다. 예 "0에서 시작"색인을 포함시켜 5x10으로 계산했습니다. 또한, 테스트 된 range-for 루프는 완벽하게 작동합니다. RESERVED의 값을 변경할 수는 없지만 range-for 루프를 사용하는 것은 그리 큰 문제가 아닙니다. 나는 아마 이것을 overthinking했다. – Simog