将模板生成的 class 分配给具有相同布局的 C 结构

Assigning a template-generated class to a C struct with the same layout

如果我没理解错的话,对象'A'是这样定义的:

typedef struct {
    int n;
    float *p;
} myStruct;
myStruct A;

是一个聚合,在内存中的布局与对象“B”完全相同,定义为:

template <typename T> class myTemplateClass
{
public:
    int n;
    T*  p;
};
myTemplateClass<float> B;

那么,有没有更优雅的赋值方式

A = B;

不用写

A = *(reinterpret_cast< myStruct *>(&B));

每次?

我问的原因是我必须调用一个库函数,该函数公开一个带有“myStruct”形式参数的接口,从以 myTemplateClass 形式保存我的数据的代码更加自然。

根据类型参数,您可以使 myTemplateClass<T> 从正确的 myStruct 派生。您可以为此使用模板专业化:

template <typename T> class myTemplateClass;

// Specialization for float
template <> class myTemplateClass<float> : public myStruct {};

// Specialization for int
template <> class myTemplateClass<int> : public myOtherStruct {};

// And so on for other types...

这样,您可以将 myTemplateClass<float> 的实例分配给 myStruct,将 myTemplateClass<int> 的实例分配给 myOtherStruct。 (奖励:您不必依赖 "same memory layout" 猜测。)

如果您从 mystruct 派生,那么,您可以在其上使用 static_cast。 如上所述,模板专业化也可以。 我每天都会 static_cast 而不是 reinterpret_cast。

下面是工作代码。

typedef struct {
    int n;
    float *p;
} myStruct;
myStruct A;



template <typename T> class myTemplateClass:public myStruct
{
public:
    int n;
    T*  p;
};
//myTemplateClass<float> B;

typedef myTemplateClass<float> temp;


temp B;

int main()
{


    A = *(static_cast< myStruct *>(&B));

这需要一些样板文件。每个 myStruct 有两个函数,每个 template.

有两个函数

myStruct的命名空间中注入这两个函数:

auto members( myStruct& s ) {
  return std::tie(s.n, s.p);
}
auto members( myStruct const& s ) {
  return std::tie(s.n, s.p);
}

在 C++11 中你必须添加一个 decltype 子句来显式地给出 return 值。基本上 tie 成员的声明顺序完全相同。

myTemplateClass 的主体中,声明一个 friend 函数 members 来做类似的事情:

template <typename T>
class myTemplateClass {
public:
  int n;
  T*  p;
  friend auto members( myTemplateClass<T>& self ) {
    return std::tie( self.n, self.p );
  }
  friend auto members( myTemplateClass<T> const& self ) {
    return std::tie( self.n, self.p );
  }
};    

最后写赋值:

template<class Lhs, class Rhs>
void assign_by_members( Lhs& lhs, Rhs const& rhs ) {
  members(lhs) = members(rhs);
}

我们完成了。

任何声明自由函数 members 且 return 可分配给其他 members 的东西的任何人都可以工作。 tie 对引用进行逐元素赋值,所以一切都很好。

请注意,只有分配的那个需要membersconst&重载,并且只有分配给[的那个[=] =58=] 需要 members& 重载。因此,如果赋值总是从 template class 到 C-struct,您可以将样板代码减半。

如果你不喜欢 assign_by_members 语法,你可以重写 operator O 如下:

template <typename T>
class myTemplateClass {
public:
// ... see above for code that goes here
  template<class O,class=decltype(members(std::declval<O>())>
  operator O() const {
    O retval;
    assign_by_members( retval, *this );
    return retval;
  }
};

它还进行测试以确定转换为的类型是否支持 members。您可以更进一步,测试 members return 值是否可以从 members(*this) 的 return 值分配给 return 值,但这会增加更多样板文件。