C++中的高效模板化结构

Efficient Templated-structures in C++

本文关键字:结构 高效 C++      更新时间:2023-10-16

我想使用模板化结构来模拟 4 个维度的双精度数组,每个维度的最大大小在编译时已知。因此,我认为使用模板结构将有机会获得性能。您可以在下面找到我对实现的尝试。除非我尝试实例化一个结构,否则代码将编译。我不明白下面的代码有什么问题,建议将不胜感激。

更重要的是,如果可能的话,我想做两个改进:1)我希望能够使用浮点型和双精度类型的数据2)希望有某种重载运算符,能够以类似于T(N,L,M,J)=val代替必须使用T.assign(N,L,M,J,值)。同样,建议将不胜感激。

我的目标是尽快以T_4D填充数据。

#include <iostream>
#include <cstring> // for memset                                                                                                                                                                                                             
using namespace std;
template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10,double *data=NULL>
struct T_4D {
  enum {SIZE = dim_N*dim_L*dim_M*dim_J };
  enum {LEN1 = dim_N };
  enum {LEN2 = dim_L };
  enum {LEN3 = dim_M };
  enum {LEN4 = dim_J };

  static void create()
  {
    data=(double *)malloc(SIZE*sizeof(double));
    memset(data, 0.0, SIZE*sizeof(*data));
  }
  static size_t multi_index(const size_t N) {
    return N;
  }
  static size_t multi_index(const size_t N,const size_t L) {
    return L*dim_N + N;
  }
  static size_t multi_index(const size_t N,const size_t L, const size_t M) {
    return (M*dim_L + L)*dim_N + N;
  }
  static size_t multi_index(const size_t N,const size_t L, const size_t M,const size_t J) {
    return ((J*dim_M + M)*dim_L + L)*dim_N + N;
  }
  double operator()(size_t N,size_t L, size_t M, size_t J){
    return data[multi_index(N,L,M,J)];
  }
  static void assign(size_t N,size_t L, size_t M, size_t J,double value){
    data[multi_index(N,L,M,J)]=value;
    }

};
int main()
{
  double *instance;
  T_4D<3,3,3,10,instance> T;
  T.create();
  return 0;
}

编译错误为:

./main.cpp: In function ‘int main()’:
./main.cpp:49:17: error: the value of ‘instance’ is not usable in a constant expression
   T_4D<3,3,3,10,instance> T;
                 ^
./main.cpp:48:11: note: ‘instance’ was not declared ‘constexpr’
   double *instance;
           ^
./main.cpp:49:25: error: ‘instance’ is not a valid template argument because ‘instance’ is a variable, not the address of a variable
   T_4D<3,3,3,10,instance> T;
                         ^
./main.cpp:50:5: error: request for member ‘create’ in ‘T’, which is of non-class type ‘int’
   T.create();
     ^
Makefile:197: recipe for target 'obj/main.o' failed
make: *** [obj/main.o] Error 1

如果在编译时知道所有维度,则无需分配动态内存。只需使用:

std::aligned_storage_t<sizeof( T ) * SIZE, alignof( T )> data;

甚至不需要初始化任何内容,因为您正在使用 POD 类型。如果你想把内存清零,只需使用这个:

for ( std::size_t i = 0; i < SIZE; ++i )
    *( reinterpret_cast<T*>( &data ) + i ) = 0;

这将是最有效的实现,因为我们使用静态连续内存。您必须实现正确的索引,但这并不太困难。

实际上,只需使用T data[ SIZE ];std::array<T, SIZE> data

此外,请删除 double* 模板参数,这些参数无法更改,因此不能用于您的数据。

使用 double* data = NULL 作为模板参数似乎不正确。您可以将double*用作模板参数,但不能像使用时那样分配给它:

data=(double *)malloc(SIZE*sizeof(double));

您可以将其作为模板参数删除,并使其成为类的成员变量。

template <size_t dim_N=3,size_t dim_L=3,size_t dim_M=3,size_t dim_J=10>
struct T_4D {
  double* data;
  ...

然后在构造函数中而不是在 static 成员函数中为其分配内存。

T_4D() : data(new double[SIZE])
{
   memset(data, 0.0, SIZE*sizeof(*data));
}

请记住遵循三法则和五法则,因为您正在从堆中分配内存。

然后,main可以简单地:

int main()
{
  T_4D<3,3,3,10> T;
  return 0;
}