将模板生成的类分配给具有相同布局的C结构
如果我理解正确,那么对象’A’定义如下:
typedef struct { int n; float *p; } myStruct; myStruct A;
是一个聚合,其内存布局与对象’B’完全相同,定义如下:
template class myTemplateClass { public: int n; T* p; }; myTemplateClass B;
那么,是否有更优雅的分配方式
A = B;
而不是写
A = *(reinterpret_cast(&B));
每次?
我的理由是我必须调用一个库函数,该函数使用“myStruct”forms的参数公开一个接口,从代码中以myTemplateClass的forms保存我的数据是非常自然的。
这需要一些样板。 每个myStruct
两个函数,每个template
两个函数。
在myStruct
的命名空间中注入以下两个函数:
auto members( myStruct& s ) { return std::tie(sn, sp); } auto members( myStruct const& s ) { return std::tie(sn, sp); }
在C ++ 11中,您必须添加一个decltype
子句以显式提供返回值。 基本上按照声明的确切顺序tie
成员。
在myTemplateClass
的主体中,声明一个执行类似操作的friend
函数members
:
template class myTemplateClass { public: int n; T* p; friend auto members( myTemplateClass& self ) { return std::tie( self.n, self.p ); } friend auto members( myTemplateClass const& self ) { return std::tie( self.n, self.p ); } };
最后,写分配:
template void assign_by_members( Lhs& lhs, Rhs const& rhs ) { members(lhs) = members(rhs); }
我们完成了。
声明自由函数members
任何人都返回可分配给其他members
东西。 tie
对引用进行了元素分配,所以一切都很好。
请注意,只有被分配的一个需要members
的const&
重载,并且只有被分配的一个需要members
的&
过载。 因此,如果赋值始终从template
类转到C- struct
,则可以将该样板减半。
如果您不喜欢assign_by_members
语法,则可以按如下方式覆盖operator O
:
template class myTemplateClass { public: // ... see above for code that goes here template())> operator O() const { O retval; assign_by_members( retval, *this ); return retval; } };
它还进行测试以确定转换为支持members
的类型。 您可以更进一步测试members
返回值是否可以从members(*this)
的返回值members(*this)
分配,但这会增加更多的样板。
您可以根据类型参数从正确的myStruct
派生myTemplateClass
。 您可以使用模板专门化:
template class myTemplateClass; // Specialization for float template <> class myTemplateClass : public myStruct {}; // Specialization for int template <> class myTemplateClass : public myOtherStruct {}; // And so on for other types...
这样,您可以将myTemplateClass
实例分配给myStruct
,将myTemplateClass
分配给myOtherStruct
。 (额外奖励:您不必依赖“相同的内存布局”猜测。)
如果你从mystruct派生,那么,你可以在它上面使用static_cast。 如上所述,模板专业化也会起作用。 我会在任何一天将static_cast放在reinterpret_cast上。
以下是工作代码。
typedef struct { int n; float *p; } myStruct; myStruct A; template class myTemplateClass:public myStruct { public: int n; T* p; }; //myTemplateClass B; typedef myTemplateClass temp; temp B; int main() { A = *(static_cast< myStruct *>(&B));