我正在处理C中的联合,我希望有一个函数模板,它可以根据模板参数访问活动的union成员.
代码就像(doSomething只是一个例子):
union Union { int16_t i16; int32_t i32; }; enum class ActiveMember { I16,I32 } template <ActiveMember M> void doSomething(Union a,const Union b) { selectMemeber(a,M) = selectMember(b,M); // this would be exactly (not equivalent) the same // that a.X = b.X depending on T. }
为了实现这一点,我只发现了一些糟糕的黑客攻击,比如专业化,或者是一种不同类的访问和分配方式.
我错过了什么,这样的事情应该用其他方法来做?
解决方法
可能性1
而不是使用枚举,您可以使用简单的结构来选择成员:
typedef short int16_t; typedef long int32_t; union Union { int16_t i16; int32_t i32; }; struct ActiveMemberI16 {}; struct ActiveMemberI32 {}; template <typename M> void doSomething(Union& a,Union b) { selectMember(a,M()) = selectMember(b,M()); // this would be exactly (not equivalent) the same // that a.X = b.X depending on T. } int16_t& selectMember(Union& u,ActiveMemberI16) { return u.i16; } int32_t& selectMember(Union& u,ActiveMemberI32) { return u.i32; } int main(int argc,char* argv[]) { Union a,b; a.i16 = 0; b.i16 = 1; doSomething<ActiveMemberI16>(a,b); std::cout << a.i16 << std::endl; b.i32 = 3; doSomething<ActiveMemberI32>(a,b); std::cout << a.i32 << std::endl; return 0; }
这需要为union中的每个成员定义struct和selectMember方法,但至少可以在许多其他函数中使用selectMember.
请注意,我将参数转换为引用,如果不合适,您可以调整它.
可能性2
通过将union指针强制转换为所需的类型指针,您可以使用单个selectMember函数.
typedef short int16_t; typedef long int32_t; union Union { int16_t i16; int32_t i32; }; template <typename T> T& selectMember(Union& u) { return *((T*)&u); } template <typename M> void doSomething(Union& a,Union b) { selectMember<M>(a) = selectMember<M>(b); // this would be exactly (not equivalent) the same // that a.X = b.X depending on T. } int _tmain(int argc,_TCHAR* argv[]) { Union a,b; a.i16 = 0; b.i16 = 1; doSomething<int16_t>(a,b); std::cout << a.i16 << std::endl; b.i32 = 100000; doSomething<int32_t>(a,b); std::cout << a.i32 << std::endl; return 0; }