【问题标题】:How to better handle a class member type that depends on template parameters?如何更好地处理依赖于模板参数的类成员类型?
【发布时间】:2012-04-03 23:52:54
【问题描述】:

我正在尝试编写一些代码来将原生 C++ 类型的数组转换为由 OpenCL 标准定义的适当大小的向量类型。

字节序和打包是特定于 OpenCL 实现的。 OpenCL 类型不提供方便的操作符[]。 (实际上 API 是 C )另一个问题:cl_int4 有一个 .s3 成员,但 cl_int2 没有。

我有一些在功能上有效的东西,但你可以看到我已经进入了疯狂的模板领域。

能否以更好的方式做到这一点?这些函数不会经常被调用,所以更好将是减少程序二进制大小和缩短源代码长度的组合.

这是我到目前为止所得到的。我不会向您展示所有维度的特化(省略 3-6),而且我也想至少实现整数类型。

#include <CL/cl.h>

template < typename HOST_T, int NUM_DIM >
struct Payload_t;

// Vector length needs to be (for dims 1-6):  2, 4, 8, 8, 16, 16

//single precision

template < >
struct __attribute__((packed)) Payload_t <float, 1> { 
    cl_float2 vec;
    void setElement( int pos, float value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            default: return;
        }
    }
};

template < >
struct __attribute__((packed)) Payload_t <float, 2> { 
    cl_float4 vec;
    void setElement( int pos, float value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            case 2: vec.s2 = value; return;
            case 3: vec.s3 = value; return;
            default: return;
        }
    }
};

/// double-precision

template < >
struct __attribute__((packed)) Payload_t <double, 1> { 
    cl_double2 vec;
    void setElement( int pos, double value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            default: return;
        }
    }
};

template < >
struct __attribute__((packed)) Payload_t <double, 2> { 
    cl_double4 vec;
    void setElement( int pos, double value )
    {
        switch (pos) {
            case 0: vec.s0 = value; return;
            case 1: vec.s1 = value; return;
            case 2: vec.s2 = value; return;
            case 3: vec.s3 = value; return;
            default: return;
        }
    }
};

我想你可能会好奇我会如何使用这个类。在一个示例中,我有一个以 REAL 类型为模板的类,它具有以下成员类的实例,其中有一个 Payload_t 的实例。

template <int NUM_DIM >
struct cartesian_box_descriptor_t : cartesian_box_descriptor_base_t
{
    static const int vectorLengthArray[6];
    void set_dx( REAL * dx_vec )
    {
        for (int i = 0; i < NUM_DIM; ++i)
            payload.setElement( i, dx_vec[i] );
    };
    void set_startx( REAL * startx_vec )
    {
        for (int i = 0; i < NUM_DIM; ++i)
            payload.setElement( NUM_DIM + i , startx_vec[i] );
    };

    virtual WxAny getDescriptorStruct() const
    {
        return WxAny( payload ); // packages this simple structure as 'scalar' with hidden type
    };


    Payload_t< REAL, NUM_DIM> payload;
};

getDescriptorStruct() 打包 OpenCL 支持的类型,我可以将其作为内核参数发送到 OpenCL API,所有字节都在正确的位置。

如果有人正在考虑范式转换,我只需要一次设置整个向量。

【问题讨论】:

标签: c++ templates opencl specialization


【解决方案1】:

我不确定是该为此感到自豪还是感到羞耻,但它确实有效。您确实需要确保对 set() 的所有调用都使用正确的类型。它自动处理新的 cl_ 类型和新大小的 cl_ 类型,仅在 3 个位置进行更改。如果有人愿意,它可能会被进一步清理。

#include<iostream>
#include<assert.h>

struct cl_float1 {
  float s0;
};

struct cl_float2 {
  float s0;
  float s1;
};


#define ZERO_THROUGH_15(pre) \
  pre i0;            \
  pre i1;            \
  pre i2;            \
  pre i3;            \
  pre i4;            \
  pre i5;            \
  pre i6;            \
  pre i7;            \
  pre i8;            \
  pre i9;            \
  pre i10;           \
  pre i11;           \
  pre i12;           \
  pre i13;           \
  pre i14;           \
  pre i15


template<typename SIMD, typename POD>
struct offset {
  static POD SIMD::* data[16];
  ZERO_THROUGH_15(static bool);
  offset() {
    ZERO_THROUGH_15();
  }
};
template<typename SIMD, typename POD>
/*static*/ POD SIMD::* offset<SIMD,POD>::data[16];

template<int n>
struct offsetGetter {
  template<typename SIMD, typename POD>
  static POD SIMD::* get(...) {
    return NULL;
  }
};

#define GET_OFFSET(n) \
template<> \
struct offsetGetter<n> { \
  template<typename SIMD, typename POD, POD SIMD::* OFS> \
  struct check {}; \
\
  template<typename SIMD, typename POD> \
  static POD SIMD::* get(check<SIMD, POD, &SIMD::s ## n>*) { \
    return &SIMD::s ## n; \
  } \
\
  template<typename SIMD, typename POD> \
  static POD SIMD::* get(...) { \
    return NULL; \
  } \
  template<typename SIMD, typename POD> \
  static bool init() { \
    offset<SIMD,POD>::data[n] = get<SIMD,POD>(NULL);    \
  }; \
}; \
template<typename SIMD, typename POD> \
 /*static*/ bool offset<SIMD,POD>::i##n = offsetGetter<n>::init<SIMD,POD>()

GET_OFFSET(0);
GET_OFFSET(1);
GET_OFFSET(2);
GET_OFFSET(3);
GET_OFFSET(4);
GET_OFFSET(5);
GET_OFFSET(6);
GET_OFFSET(7);
GET_OFFSET(8);
GET_OFFSET(9);
GET_OFFSET(10);
GET_OFFSET(11);
GET_OFFSET(12);
GET_OFFSET(13);
GET_OFFSET(14);
GET_OFFSET(15);

template<typename SIMD, typename POD>
void set(SIMD& simd, int n, POD val) {
  offset<SIMD,POD> ignoreme;
  POD SIMD::* ofs = offset<SIMD,POD>::data[n];
  assert(ofs);
  simd.*ofs = val;
}

main(){
  cl_float2 x;
  set(x, 0, 42.0f);
  std::cout << x.s0 << std::endl; // prints 42
  set(x, 1, 52.0f);
  std::cout << x.s1 << std::endl; // prints 52
  cl_float1 y;
  set(y, 1, 42.0f); // assertion failure
}

【讨论】:

  • 哇。我一直在努力解决这个问题。现在有几点注意事项。 cl_float1 不是 OpenCL 类型,而是 cl_float。我用我的示例代码中的 OpenCL 标头替换了两个结构定义。通过这些更改,我收到来自assert(ofs) 行的断言错误,甚至在main() 中的任何set() 行之前。我也收到了 80 个警告,我认为所有与 static bool init() 函数相关的内容都不会返回。你能评论一下这两个问题吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
相关资源
最近更新 更多