问题
If I understand correctly, the object ’A’ defined thus:
typedef struct {
int n;
float *p;
} myStruct;
myStruct A;
is an aggregate with exactly the same layout in memory as the object ‘B’ defined as:
template <typename T> class myTemplateClass
{
public:
int n;
T* p;
};
myTemplateClass<float> B;
So, is there a more elegant way of assigning
A = B;
than having to write
A = *(reinterpret_cast< myStruct *>(&B));
every time?
My reason for asking is that I have to call a library function which exposes an interface with arguments of the form ‘myStruct’, from code where holding my data in the form of myTemplateClass is a great deal more natural.
回答1:
This requires a bit of boilerplate. Two functions per myStruct, and two functions per template.
In the namespace of myStruct inject these two functions:
auto members( myStruct& s ) {
return std::tie(s.n, s.p);
}
auto members( myStruct const& s ) {
return std::tie(s.n, s.p);
}
in C++11 you have to add a decltype clause to give the return value explicitly. Basically tie the members in the exact order declared.
In the body of the myTemplateClass, declare a friend function members that does something similar:
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 );
}
};
finally, write assign:
template<class Lhs, class Rhs>
void assign_by_members( Lhs& lhs, Rhs const& rhs ) {
members(lhs) = members(rhs);
}
and we are done.
Anyone that declares a free function members that returns something assignable to the other members works. tie does element-wise assign on references, so all is good.
Note that only the one being assigned from needs the const& overload of members and only the one being assigned to needs the & overload of members. So if assignment always goes from template class to C-struct, you can halve that boilerplate.
If you don't like the assign_by_members syntax, you can override operator O as follows:
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;
}
};
which also does a test to determine if the type converted to supports members. You could go a step further and test if the members return value can be assigned to from the return value of members(*this), but that adds more boilerplate.
回答2:
You could make myTemplateClass<T> derive from the correct myStruct depending on the type parameter. You can use template specialization for this:
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...
This way, you can assign instances of myTemplateClass<float> to myStruct, and myTemplateClass<int> to myOtherStruct. (Bonus: You don't have to rely on the "same memory layout" guess.)
回答3:
If you derive from mystruct, then, u can use a static_cast on it. As suggested above, template specialization would work too. I would take static_cast over reinterpret_cast any day.
Below is the working code.
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));
来源:https://stackoverflow.com/questions/28157895/assigning-a-template-generated-class-to-a-c-struct-with-the-same-layout