Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Шаблонный класс, реализующий многомерный массив [закрыт]

#cpp #cpp11 #cpp14


        
             
                
                    
                        
                            Closed. This question needs to be more focused. It is
not currently accepting answers.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Want to improve this question? Update the question so
it focuses on one problem only by editing this post.
                        
                        Closed 3 года назад.
                                                                                
           
                
        
Пока не совсем дружу с шаблонами, прошу пример реализации многомерного массива на
основе шаблонов. Чтобы использовался примерно так:

// ...
Matrix M1(10); // массив с одним измерением
Matrix M2(2,3,4); // массив с тремя измерениями
Matrix M3; // и такой вариант вызова устроит
// ...
M2.At(1,1,0) = "элемент массива";
// ...


Что дополнительно нужно:


нужна только реализация конструктора и метода At, возвращающего ссылку на нужный
элемент многомерного массива
если в конструкторе вообще аргументов нет - нужен вызов static_assert
ecли в методе At количество аргументов не соответствует количеству аргументов конструктора
- нужен вызов static_assert
ecли в методе At аргументы выходят за диапазон - нужен проброс std::range_error
содержимое многомерного массива строить на основе std::vector


Весьма буду признателен за мастер-класс! :-)

Мой "сырой" вариант, в процессе доработки ...

#include 
#include 

template
class Matrix {
  public:
    Matrix() {
     // собираем "измерения"
     DimVars = {Dims...};
     // резервируем "ячейки" в одномерном массиве
     BuffLen = std::accumulate(DimVars.begin(), DimVars.end(), 1, std::multiplies());
     Buff.resize(BuffLen);
    }
    void Print() {
      for(const auto &i:DimVars) std::cout << i << ":";
      std::cout << "\n";
    }
  private:
    std::vector DimVars;
    std::vector Buff;
    std::size_t BuffLen;
};

int main() {
  try {
    Matrix M1;
    M1.Print();
    Matrix M2;
    M2.Print();
  } catch(...) {
    std::cout << "Error\n";
  }
  return 0;
}

    


Ответы

Ответ 1



Пришёл к такому варианту: template using AreCorrectIndicies_t = std::tuple::value>...>; template class Matrix { public: Matrix() { std::array dimensions{Dimensions...}; size_t size = std::accumulate(dimensions.begin(), dimensions.end(), size_t{1}, std::multiplies<>{}); m_Container.resize(size); } template> T& At(Values... indicies) { static_assert(sizeof...(indicies) == sizeof...(Dimensions), "Dimensions don't match!"); std::array input{static_cast(indicies)...}; std::array dimensions{Dimensions...}; for(size_t i = 0; i < input.size(); ++i) { if(input[i] >= dimensions[i]) throw std::runtime_error{"Wrong indicies"}; } return _getElement(input); } private: T& _getElement(const std::array& indicies) { return m_Container[_calculateIndex(indicies)]; } size_t _calculateIndex(const std::array& indicies) { std::array dimensions{Dimensions...}; size_t internalIndex = 0; for(size_t i = 0; i < indicies.size(); ++i) { auto span = std::accumulate(dimensions.begin() + i + 1, dimensions.end(), indicies[i], std::multiplies<>{}); internalIndex += span; } return internalIndex; } private: std::vector m_Container; }; Идея проста: плоский массив, в котором индекс высчитывается при обращении. Многое в этом коде можно доработать, оптимизировать и улучшить. К примеру, std::vector тут вообще не нужен, его можно заменить на std::array и т.п. Пример использования на ideone.

Комментариев нет:

Отправить комментарий