2013-04-13 2 views
2

배열을 사용하여 Matrix 데이터를 저장할 수 있음을 알고 있습니다. 행렬 큰되고 당신이 스택 공간균일 한 초기화 및 생성자를 결합 할 수 있습니까?

Matrix m(2, 2) = { 1, 2 
        3, 4 }; 

수이 (또는 뭔가 부족할 때

Matrix<2, 2> m = { 1, 2 
        3, 4 }; 

하지만 배열을 사용하는 것으로,이 작업을 수행하는 대신 벡터를 사용하고자하는 아주 나쁜 비슷한) 할 수 있습니까?

+0

물론,'std :: initializer_list '을 허용하는 생성자를 작성할 수 있습니다. –

+0

@KerrekSB : 확실합니까? AFAICT 이것이 불가능합니다 ([live example] (http://liveworkspace.org/code/3kW04t$309)) –

+0

그 구문을 지키지 않거나 약간 다른 호출이 괜찮습니까? – delnan

답변

2

컴파일 타임에는 고정 크기이지만 동적 할당을 사용하려는 경우 각 개체의 할당 유형 ("스택"/ "힙")을 개별적으로 선택하거나 동적 할당을 Matrix 수업.

Matrix 클래스 외부의 동적 할당의 예입니다. initializer-lists를 사용하면 컴파일시에 전달 된 요소의 수를 확인할 수 없습니다 (contexpr 인스턴스를 Matrix로 선언하는 것 외에는 제외). 따라서 컴파일 시간 크기 검사를 보여주기 위해 다소 바보 같은 추가 기능을 도입했습니다. 위의 예에서

#include <memory> 
#include <iostream> 
#include <array> 

template < typename T, std::size_t rows, std::size_t columns > 
struct Matrix 
{ 
public: 
    Matrix(std::initializer_list<T> p) 
    { 
     if(p.size() != rows*columns) { /* throw */ } 

     std::copy(p.begin(), p.end(), storage_member.begin()); 
    } 
    Matrix(std::array<T, columns*rows> const& p) 
    { 
     std::copy(p.begin(), p.end(), storage_member.begin()); 
    } 

    Matrix(std::initializer_list< std::initializer_list<T> > p) 
    { 
     if(p.size() != rows) { /* throw */ } 

     auto itRow = p.begin(); 
     for(std::size_t row = 0; row < rows; ++row, ++itRow) 
     { 
      if(itRow->size() != columns) { /* throw */ } 

      auto itCol = itRow->begin(); 
      for(std::size_t col = 0; col < columns; ++col, ++itCol) 
      { 
      storage_member[col+row*columns] = *itCol; 
      } 
     } 
    } 
    Matrix(std::array<std::array<T, columns>, rows> const& p) 
    { 
     for(std::size_t row = 0; row < rows; ++row) 
     { 
      for(std::size_t col = 0; col < columns; ++col) 
      { 
      storage_member[col+row*columns] = p[row][col]; 
      } 
     } 
    } 

    // getters, setters 
    T& operator() (std::size_t row, std::size_t col) 
    { 
     return storage_member[col+row*columns]; 
    } 
private: 
    // storage, e.g. 
    std::array<T, columns*rows> storage_member; 
}; 

template < typename T, typename... TP> 
constexpr std::array<T,sizeof...(TP)+1> m(T&& p, TP... pp) 
{ 
    return {{p, pp...}}; 
} 

// usage: 
int main() 
{ 
    using My_Matrix_Type = Matrix < int, 2, 2 >; 

    std::unique_ptr <My_Matrix_Type> pmyMatrix0{ new My_Matrix_Type({1,2,3,4}) }; 
    std::unique_ptr <My_Matrix_Type> pmyMatrix1{ new My_Matrix_Type({{1,2},{3,4}}) }; 

    // with compile-time size checks 
    std::unique_ptr <My_Matrix_Type> pmyMatrix2{ new My_Matrix_Type(m(1,2,3,4)) }; 
    std::unique_ptr <My_Matrix_Type> pmyMatrix3{ new My_Matrix_Type(m(m(1,2), m(3,4))) }; 
    // a more fancy but possible syntax, would require some additional effort: 
    //std::unique_ptr <My_Matrix_Type> pmyMatrix4{ new My_Matrix_Type(b(1,2)(3,4)) }; 


    std::cout << (*pmyMatrix0)(1,1) << std::endl; 
    std::cout << (*pmyMatrix1)(1,1) << std::endl; 
    std::cout << (*pmyMatrix2)(1,1) << std::endl; 
    std::cout << (*pmyMatrix3)(1,1) << std::endl; 
} 

, 즉시 동적 할당 내장을 만들기 위해 동적으로 할당 된 배열에 의해 storage_member을 대체 할 수 있습니다.

당신이 컴파일 타임에 크기를 알 수없는 경우

, 당신은 (위에서 언급 한대로) Matrix 클래스에 동적 할당을 구축했다. 2 단계 초기화 목록의 크기 (행, 행)를 추론 할 수 있으므로 고정 크기 배열을 사용하는 ctors를 제거하고 다음과 같이 1 단계 초기화 목록을 가져 오는 식별자 만 변경하면됩니다.

template < typename T > // no size parameters! 
struct Matrix 
{ 
    Matrix(std::size_t columns, std::size_t rows, std::initializer_list<T> p); 
    Matrix(std::initializer_list< std::initializer_list<T> > p); 
    // maybe an additional ctor for dynamically allocated arrays 

    // getters, setters, data members 
}; 

// usage: 
Matrix myMatrix0(2, 2, {1,2,3,4}); 
Matrix myMatrix1({{1,2},{3,4}}); 
+0

누구나'make_unique' (이니셜 라이저 목록이있는 특히 예제)로이 작업을 수행하는 방법을 알고 있다면, 나는 주석/편집을 부탁드립니다. – dyp

관련 문제