C++ 中的高效模板结构

Efficient Templated-structures in C++

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

更重要的是,如果可能的话,我想做两个改进:1) 我希望能够使用 float 类型和 double 类型的数据 2) 会喜欢有某种重载运算符来赋值以类似于 T(N,L,M,J)=val 的方式将值添加到数据记录中,而不必使用 T.assign(N,L,M,J,value)。再次,非常感谢您的建议。

我的目标是尽快将数据填入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

使用double* data = NULL作为模板参数似乎不对。您可以使用 double* 作为模板参数,但不能像使用以下方法那样分配给它:

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

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

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));
}

记住要遵循The Rule of Three and The Rule of Five,因为你是从堆中分配内存。

那么,main 可以简单地是:

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

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

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* 模板参数,这些无法更改,因此不能用于您的数据。