Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何制作一个;可变的;类向量类_C++_C++11_Vector_Variadic - Fatal编程技术网

C++ 如何制作一个;可变的;类向量类

C++ 如何制作一个;可变的;类向量类,c++,c++11,vector,variadic,C++,C++11,Vector,Variadic,我试图使类充当多维向量。它不需要做任何花哨的事情。我基本上希望有一个“container”类foo,在这里我可以通过foo[x][y][z]访问元素。现在我还需要类似的foo[x][y]和foo[x]类。这让我思考了下面的(更一般的)问题,有没有一种方法可以让这样的东西,你可以对任意n个参数初始化为fooa(a,b,c,…),然后得到一个n维向量,其中的元素可以被[]访问。。。?下面是四维的例子 首先是标题 #ifndef FCONTAINER_H #define FCONTAINE

我试图使类充当多维向量。它不需要做任何花哨的事情。我基本上希望有一个“container”类foo,在这里我可以通过foo[x][y][z]访问元素。现在我还需要类似的foo[x][y]和foo[x]类。这让我思考了下面的(更一般的)问题,有没有一种方法可以让这样的东西,你可以对任意n个参数初始化为fooa(a,b,c,…),然后得到一个n维向量,其中的元素可以被[]访问。。。?下面是四维的例子

首先是标题

   #ifndef FCONTAINER_H
   #define FCONTAINER_H
   #include <iostream>
   using namespace std;

   class Fcontainer
   {
   private:
           unsigned dim1, dim2, dim3, dim4 ;
           double* data;
   public:
           Fcontainer(unsigned const dims1, unsigned const dims2, unsigned const dims3, unsigned const dims4);
           ~Fcontainer();

           Fcontainer(const Fcontainer& m);
           Fcontainer& operator= (const Fcontainer& m);

           double& operator() (unsigned const dim1, unsigned const dim2, unsigned const dim3, unsigned const dim4);
           double const& operator() (unsigned const dim1, unsigned const dim2, unsigned const dim3, unsigned const dim4) const;
    };
    #endif // FCONTAINER_H

所以我想把它扩展到任意数量的维度。我想这将需要一些变量模板或std::initializer_列表,但我不清楚如何解决这个问题

好吧,假设您关心效率,那么您可能希望以连续的方式存储所有元素。因此,您可能希望执行以下操作:

template <std::size_t N, class T>
class MultiArray {
    MultiArray(const std::array<std::size_t, N> sizes)
      : m_sizes(sizes)
      , m_data.resize(product(m_sizes)) {}

    std::array<std::size_t, N> m_sizes;
    std::vector<T> m_data;
};
最后,当您完成最后一个索引时,您有一个专门化:

   template <>
   class Indexor<N-1> { // with obvious constructor
       auto operator[](std::size_t index) {
           m_indices[N-1] = index;
           return m_parent.m_data[indexed_product(m_indices, m_parent.m_sizes)];
       }
       std::array<std::size_t, N> m_indices;
       MultiArray& m_parent;
   };

Edit2:我在实现中使用
product
index\u product
。第一个是显而易见的,第二个不是那么明显,但希望它们应该是清楚的。后者是一个函数,给定一个维度数组和一个索引数组,它将返回该元素在数组中的位置。

在Visual Studio中胡闹了一会儿,我想出了一个无稽之谈:

template<typename T>
class Matrix {
    std::vector<size_t> dimensions;
    std::unique_ptr<T[]> _data;

    template<typename ... Dimensions>
    size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
        dimensions.emplace_back(dim);
        return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
    }

    size_t apply_dimensions(size_t dim) {
        dimensions.emplace_back(dim);
        return dim;
    }
public:
    Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
        size_t size = flat_size();
        _data = std::make_unique<T[]>(size);
    }

    template<typename ... Dimensions>
    Matrix(size_t dim, Dimensions&&... dims) {
        size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
        _data = std::make_unique<T[]>(size);
    }

    T & operator()(std::vector<size_t> const& indexes) {
        if(indexes.size() != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        return _data[get_flat_index(indexes)];
    }

    T const& operator()(std::vector<size_t> const& indexes) const {
        if (indexes.size() != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        return _data[get_flat_index(indexes)];
    }

    template<typename ... Indexes>
    T & operator()(size_t idx, Indexes&& ... indexes) {
        if (sizeof...(indexes)+1 != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
        return at(flat_index);
    }

    template<typename ... Indexes>
    T const& operator()(size_t idx, Indexes&& ... indexes) const {
        if (sizeof...(indexes)+1 != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
        return at(flat_index);
    }

    T & at(size_t flat_index) {
        return _data[flat_index];
    }

    T const& at(size_t flat_index) const {
        return _data[flat_index];
    }

    size_t dimension_size(size_t dim) const {
        return dimensions[dim];
    }

    size_t num_of_dimensions() const {
        return dimensions.size();
    }

    size_t flat_size() const {
        size_t size = 1;
        for (size_t dim : dimensions)
            size *= dim;
        return size;
    }

private:
    size_t get_flat_index(std::vector<size_t> const& indexes) const {
        size_t dim = 0;
        size_t flat_index = 0;
        for (size_t index : indexes) {
            flat_index += get_offset(index, dim++);
        }
        return flat_index;
    }

    template<typename ... Indexes>
    size_t get_flat_index(size_t dim, size_t index, Indexes&& ... indexes) const {
        return get_offset(index, dim) + get_flat_index(dim + 1, std::forward<Indexes>(indexes)...);
    }

    size_t get_flat_index(size_t dim, size_t index) const {
        return get_offset(index, dim);
    }

    size_t get_offset(size_t index, size_t dim) const {
        if (index >= dimensions[dim])
            throw std::runtime_error("Index out of Bounds");
        for (size_t i = dim + 1; i < dimensions.size(); i++) {
            index *= dimensions[i];
        }
        return index;
    }
};
模板
类矩阵{
向量维数;
std::唯一的ptr数据;
模板
尺寸应用尺寸(尺寸、尺寸和…尺寸){
尺寸:后安放(尺寸);
返回尺寸*应用尺寸(标准:前进(尺寸)…);
}
尺寸应用尺寸(尺寸尺寸){
尺寸:后安放(尺寸);
返回暗淡;
}
公众:
矩阵(标准::向量dims):尺寸(标准::移动(dims)){
尺寸=平面尺寸();
_数据=标准::使_唯一(大小);
}
模板
矩阵(尺寸、尺寸和…尺寸){
尺寸=应用尺寸(尺寸,标准::正向(尺寸)…);
_数据=标准::使_唯一(大小);
}
T运算符()(标准::向量常量和索引){
if(index.size()!=dimensions.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
返回数据[get_flat_index(索引)];
}
常量和运算符()(标准::向量常量和索引)常量{
if(index.size()!=dimensions.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
返回数据[get_flat_index(索引)];
}
模板
运算符()(大小\u T idx、索引和…索引){
if(sizeof…(索引)+1!=维度.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
size_t flat_index=get_flat_index(0,idx,std::forward(索引)…);
收益率(平指数);
}
模板
常量和运算符()(大小\u T idx、索引和…索引)常量{
if(sizeof…(索引)+1!=维度.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
size_t flat_index=get_flat_index(0,idx,std::forward(索引)…);
收益率(平指数);
}
T&at(尺寸扁平指数){
返回数据[平面索引];
}
T常数和at(尺寸扁平指数)常数{
返回数据[平面索引];
}
尺寸尺寸大小(尺寸)常数{
返回尺寸[dim];
}
大小\u t数量\u的维数()常数{
返回维度。size();
}
大小\u t扁平\u大小()常数{
尺寸=1;
用于(尺寸:尺寸)
尺寸*=暗;
返回大小;
}
私人:
大小获取平面索引(标准::向量常量和索引)常量{
尺寸尺寸=0;
尺寸指数=0;
用于(大小索引:索引){
平面索引+=获取偏移量(索引,dim++);
}
返回平面指数;
}
模板
大小获取平面索引(大小、大小索引、索引和…索引)常量{
返回get_偏移量(索引,dim)+get_平坦索引(dim+1,std::forward(索引)…);
}
大小获取平面索引(大小、大小索引)常量{
返回get_偏移量(索引,dim);
}
大小获取偏移量(大小索引、大小尺寸)常量{
如果(索引>=维度[dim])
抛出std::runtime_错误(“索引超出范围”);
对于(尺寸i=dim+1;i
让我们来谈谈这段代码实现了什么

//private:
    template<typename ... Dimensions>
    size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
        dimensions.emplace_back(dim);
        return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
    }

    size_t apply_dimensions(size_t dim) {
        dimensions.emplace_back(dim);
        return dim;
    }
public:
    Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
        size_t size = flat_size();
        _data = std::make_unique<T[]>(size);
    }

    template<typename ... Dimensions>
    Matrix(size_t dim, Dimensions&&... dims) {
        size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
        _data = std::make_unique<T[]>(size);
    }
//私有:
模板
尺寸应用尺寸(尺寸、尺寸和…尺寸){
尺寸:后安放(尺寸);
返回尺寸*应用尺寸(标准:前进(尺寸)…);
}
尺寸应用尺寸(尺寸尺寸){
尺寸:后安放(尺寸);
返回暗淡;
}
公众:
矩阵(标准::向量dims):尺寸(标准::移动(dims)){
尺寸=平面尺寸();
_数据=标准::使_唯一(大小);
}
模板
矩阵(尺寸、尺寸和…尺寸){
尺寸=应用尺寸(尺寸,标准::正向(尺寸)…);
_数据=标准::使_唯一(大小);
}
这段代码使我们能够为这个矩阵编写一个初始值设定项,它具有任意数量的维度

int main() {
    Matrix<int> mat{2, 2}; //Yields a 2x2 2D Rectangular Matrix
    mat = Matrix<int>{4, 6, 5};//mat is now a 4x6x5 3D Rectangular Matrix
    mat = Matrix<int>{9};//mat is now a 9-length 1D array.
    mat = Matrix<int>{2, 3, 4, 5, 6, 7, 8, 9};//Why would you do this? (yet it compiles...)
}
intmain(){
矩阵mat{2,2};//产生一个2x2二维矩形矩阵
mat=矩阵{4,6,5};//mat现在是4x6x5三维矩形矩阵
mat=矩阵{9};//mat现在是一个9长度的1D数组。
mat=矩阵{2,3,4,5,6,7,8,9};//为什么要这样做?(但它编译了…)
}
如果只有在运行时才知道维度的数量和大小
template<typename T>
class Matrix {
    std::vector<size_t> dimensions;
    std::unique_ptr<T[]> _data;

    template<typename ... Dimensions>
    size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
        dimensions.emplace_back(dim);
        return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
    }

    size_t apply_dimensions(size_t dim) {
        dimensions.emplace_back(dim);
        return dim;
    }
public:
    Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
        size_t size = flat_size();
        _data = std::make_unique<T[]>(size);
    }

    template<typename ... Dimensions>
    Matrix(size_t dim, Dimensions&&... dims) {
        size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
        _data = std::make_unique<T[]>(size);
    }

    T & operator()(std::vector<size_t> const& indexes) {
        if(indexes.size() != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        return _data[get_flat_index(indexes)];
    }

    T const& operator()(std::vector<size_t> const& indexes) const {
        if (indexes.size() != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        return _data[get_flat_index(indexes)];
    }

    template<typename ... Indexes>
    T & operator()(size_t idx, Indexes&& ... indexes) {
        if (sizeof...(indexes)+1 != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
        return at(flat_index);
    }

    template<typename ... Indexes>
    T const& operator()(size_t idx, Indexes&& ... indexes) const {
        if (sizeof...(indexes)+1 != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
        return at(flat_index);
    }

    T & at(size_t flat_index) {
        return _data[flat_index];
    }

    T const& at(size_t flat_index) const {
        return _data[flat_index];
    }

    size_t dimension_size(size_t dim) const {
        return dimensions[dim];
    }

    size_t num_of_dimensions() const {
        return dimensions.size();
    }

    size_t flat_size() const {
        size_t size = 1;
        for (size_t dim : dimensions)
            size *= dim;
        return size;
    }

private:
    size_t get_flat_index(std::vector<size_t> const& indexes) const {
        size_t dim = 0;
        size_t flat_index = 0;
        for (size_t index : indexes) {
            flat_index += get_offset(index, dim++);
        }
        return flat_index;
    }

    template<typename ... Indexes>
    size_t get_flat_index(size_t dim, size_t index, Indexes&& ... indexes) const {
        return get_offset(index, dim) + get_flat_index(dim + 1, std::forward<Indexes>(indexes)...);
    }

    size_t get_flat_index(size_t dim, size_t index) const {
        return get_offset(index, dim);
    }

    size_t get_offset(size_t index, size_t dim) const {
        if (index >= dimensions[dim])
            throw std::runtime_error("Index out of Bounds");
        for (size_t i = dim + 1; i < dimensions.size(); i++) {
            index *= dimensions[i];
        }
        return index;
    }
};
//private:
    template<typename ... Dimensions>
    size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
        dimensions.emplace_back(dim);
        return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
    }

    size_t apply_dimensions(size_t dim) {
        dimensions.emplace_back(dim);
        return dim;
    }
public:
    Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
        size_t size = flat_size();
        _data = std::make_unique<T[]>(size);
    }

    template<typename ... Dimensions>
    Matrix(size_t dim, Dimensions&&... dims) {
        size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
        _data = std::make_unique<T[]>(size);
    }
int main() {
    Matrix<int> mat{2, 2}; //Yields a 2x2 2D Rectangular Matrix
    mat = Matrix<int>{4, 6, 5};//mat is now a 4x6x5 3D Rectangular Matrix
    mat = Matrix<int>{9};//mat is now a 9-length 1D array.
    mat = Matrix<int>{2, 3, 4, 5, 6, 7, 8, 9};//Why would you do this? (yet it compiles...)
}
int main() {
    std::cout << "Input the sizes of each of the dimensions.\n";
    std::string line;
    std::getline(std::cin, line);
    std::stringstream ss(line);
    size_t dim;
    std::vector<size_t> dimensions;
    while(ss >> dim)
        dimensions.emplace_back(dim);

    Matrix<int> mat{dimensions};//Voila.
}
//public:
    T & operator()(std::vector<size_t> const& indexes) {
        if(indexes.size() != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        return _data[get_flat_index(indexes)];
    }

    T const& operator()(std::vector<size_t> const& indexes) const {
        if (indexes.size() != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        return _data[get_flat_index(indexes)];
    }

    template<typename ... Indexes>
    T & operator()(size_t idx, Indexes&& ... indexes) {
        if (sizeof...(indexes)+1 != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
        return at(flat_index);
    }

    template<typename ... Indexes>
    T const& operator()(size_t idx, Indexes&& ... indexes) const {
        if (sizeof...(indexes)+1 != dimensions.size())
            throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
        size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
        return at(flat_index);
    }
Matrix<int> mat{6, 5};
mat(5, 2) = 17;
//mat(5, 1, 7) = 24; //throws exception at runtime because of wrong number of dimensions.
mat = Matrix<int>{9, 2, 8};
mat(5, 1, 7) = 24;
//mat(5, 2) = 17; //throws exception at runtime because of wrong number of dimensions.
std::vector<size_t> indexes;
/*...*/
mat(indexes) = 54; //Will throw if index count is wrong, will succeed otherwise