Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.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++ 表示为1D的多维数组(n维模板化)_C++_Arrays_Multidimensional Array_C++17 - Fatal编程技术网

C++ 表示为1D的多维数组(n维模板化)

C++ 表示为1D的多维数组(n维模板化),c++,arrays,multidimensional-array,c++17,C++,Arrays,Multidimensional Array,C++17,在C++中声明静态数组的多维数组非常容易,数组则存储在一个连续的内存块(行主要布局)中。 问题 然而,在C++中声明动态分配的多维数组(在运行时只知道运行的大小)是非常棘手的。要使用多个方括号保留相同的语法(在2D数组的情况下),您需要创建一个指向另一组数组(行)的指针数组。随着维数的增加,它会增加更多(不必要)级别的间接寻址、内存碎片,而对于较小的数组,指针可以占用比实际数据更多的内存 解决方案之一是使用1D数组,然后重新计算索引 例子: 尺寸为10、3和5的3D阵列。我希望在位置3,1,4处

在C++中声明静态数组的多维数组非常容易,数组则存储在一个连续的内存块(行主要布局)中。 问题

然而,在C++中声明动态分配的多维数组(在运行时只知道运行的大小)是非常棘手的。要使用多个方括号保留相同的语法(在2D数组的情况下),您需要创建一个指向另一组数组(行)的指针数组。随着维数的增加,它会增加更多(不必要)级别的间接寻址、内存碎片,而对于较小的数组,指针可以占用比实际数据更多的内存

解决方案之一是使用1D数组,然后重新计算索引

例子: 尺寸为10、3和5的3D阵列。我希望在位置3,1,4处有一个元素,而不是写
3darray[3][1][4]
我会写
3darray[index]
,其中index将计算为
3*(y_dym_size*z_dym_size)+1*(z_dym_size)+4
,替换后,结果为
3*(3*5)+1*(5)+4

我可以很容易地创建一个类来封装一个动态分配的数组,并以所示的方式在索引中重新计算,但这是不实际的,因为它需要为每个维度编写

问题: < P>我想创建一个模板,它可以为任意数量的零开销(这是现代C++的精神——具有可重用代码/类,其中更多的工作被移到编译器)。我有以下适用于n维数组的代码,但是没有0开销。它包含for循环,还包含一个用于1D分辨率的数组:

模板
类arrayND{
std::数组大小;
std::阵列存取乘法器;
矢量数据;
公众:
使用迭代器=类型名向量::迭代器;
使用常量迭代器=类型名向量::常量迭代器;
模板
arrayND(Args&…Args){
std::数组温度{args…};
尺寸=温度;
尺寸乘以=1;
对于(int i=DIM-2;i>=0;--i){
mult*=尺寸[i+1];
存取乘数[i]=mult;
}
调整数据大小(mult*temp[0]);
}
模板
T&get(Args&&…Args){
std::数组idx_copy{args…};
大小索引=idx拷贝[DIM-1];
对于(int i=DIM-2;i>=0;--i){
索引+=idx_拷贝[i]*访问乘法器[i];
}
返回数据[索引];
}
模板
运算符()(Args&&…Args){
返回get(args…);
}
无效集(常数T&elem){
填充(开始(数据)、结束(数据)、元素);
}
迭代器begin(){
返回开始(数据);
}
迭代器结束(){
返回端(数据);
}
常量迭代器begin()常量{
返回cbegin(数据);
}
常量迭代器end()常量{
返回cend(数据);
}
};
我想到的另一种方法是使用可变模板,在编译器优化后,它有望与专门为某些维度编写的代码相同:

intgetindex(大小索引){
收益指数;
}
模板
int getIndex(大小索引,参数…参数){
返回访问乘数[DIM sizeof…(Args)-1]*index+getIndex(Args;
}
模板
T&get(Args&&…Args){
返回数据[getIndex(args…);
/*std::数组idx_copy{args…};
大小索引=idx拷贝[DIM-1];
对于(int i=DIM-2;i>=0;--i){
索引+=idx_拷贝[i]*访问乘法器[i];
}
返回数据[索引]*/
}

有没有一种方法在当前版本(C++ 17)或C++语言中如何获得灵活性(任意数量的维度)和性能(零开销与特定于若干维度的代码相比)?如果必须有额外的开销,那么对它进行硬编码就更有意义了,比如说最多5维。


某些现有库中是否已经实现了dynamics多维数组?

从存储中拆分视图

T的n维数组视图是一个类,它的指针指向
T
,并以某种方式获得n-1个步幅大小<代码>[]返回n-1维数组视图

这种观点有两种不同的风格。第一个存储步幅,第二个存储指向步幅连续缓冲区的指针。两者各有优势,;当某些或所有尺寸固定时,第一种方法甚至可以进行优化。但我会做第二个

template<class T, std::size_t N>
struct slice {
  T* ptr=0;
  std::size_t const* strides=0;
  slice<T,N-1> operator[]( std::size_t i )const{
    return { ptr + i**strides, strides+1 };
  }
};
template<class T>
struct slice<T,1> {
  T* ptr=0;
  std::size_t const* strides=0;
  T& operator[]( std::size_t i )const{
    return *(ptr + i**strides);
  }
};
模板
结构切片{
T*ptr=0;
标准:尺寸常数*跨步=0;
切片运算符[](标准::大小\u t i)常量{
返回{ptr+i**strips,strips+1};
}
};
模板
结构切片{
T*ptr=0;
标准:尺寸常数*跨步=0;
T&operator[](标准::大小\u T i)常数{
返回*(ptr+i**步数);
}
};
这一个允许每个元素的步幅

现在,您只需公开一个
跨步
即可在上执行链接的
[]
。这类似于我在三维空间中的写法


如果您更喜欢
(x,y,z)
语法,并且您唯一的问题是for循环,并且担心编译器没有展平它,那么您可以使用包扩展强制展平它。但首先要分析并检查优化的组件。

静态大小的阵列不需要向量。使用
[]
实现它们的方法有很多。要么你感到困惑,要么有一些限制要求你做体操。用未说明的约束条件很难解决问题。@Yakk:他想成为一个abe来声明
arrayND small(2,2),big(200200)-维度的数量是类型的一部分,但每个维度的大小都传递给构造函数。这需要一个向量(或其他动态分配的缓冲区)。感谢Martin提供了一个与您所写的完全相同的示例@雅克:我已经更新了这个问题,明确指出这个问题与动态分配的数组有关(我没有提到)。