How can I define operations on a template without caring what type it was creating?
I inherited a bunch of networking code that defined many packet types. I have to write a bunch of conversion functions that occupy structures of a certain type, and copy the values โโinto other structures that have the same fields but in a different order (as part of a collapsed partial bit-to-bit order conversion - don ask). Also, I know there might be better ways to express conversions, etc. Below, but at the moment it does not concern me. In particular, I cannot do the conversion by taking its output variable by reference, because I will be passing in bitfields and this generates a compiler error.
So, there are a bunch of structures like this:
struct foo {
int bar;
int baz;
};
struct foo_x86 {
int baz;
int bar;
};
And a bunch of functions like this to convert between:
foo_x86 convert (const foo & in) {foo_x86 out; out.bar = in.bar; out.baz = in.baz; return; }
It doesn't really matter. I have a problem: there is also a template structure that looks something like this:
template <class T>
struct Packet {
HeaderType head;
T data;
};
There are multiple instances of this template using the above package types as template parameters, for example:
struct superfoo {
Packet<foo> quux;
};
struct superfoo_x86 {
Packet<foo_x86> quux;
};
Now, assuming that there is a function foo_x86 convert (const foo &); is there a way to create a template function to handle package objects that calls this transform function?
For example, I want something like this:
template <class type_1, class type_2>
Packet<type_2> convert(const Packet<type_1>& in) {
Packet<type_2> out;
out.head = in.head;
out.data = convert(in.data);
return out;
}
This will work with a function like:
superfoo_x86 convert(const superfoo& in) {
superfoo_x86 out;
out.quux = convert(in.quux);
return out;
}
I want to be able to convert package objects without worrying about what type they are created with, and I want to avoid having to declare separate conversion functions for all possible instances of the package.
Is there anyway to do with templates in C ++?
source to share
I ended up doing something like what was suggested in the comment on the original question. First, I created a non-specialized transform class template, for example:
template <class type_1>
struct conversion {};
Then I threw in a macro to specialize this class (which I believe is similar to the templating pattern suggested, right?), For example:
#define GEN_CON(type_1, type_2) \
template <> struct conversion<type_1> { typedef type_2 type; }
Then, for each conversion function from foo to foo_x86, I added the following macro call in the header after defining the conversion function:
foo_x86 convert (const foo&);
GEN_CON(foo, foo_x86);
This creates a transform template for foo and foo_x86, for example:
template <>
struct conversion<foo> { typedef foo_x86 type; }
Now I can turn to the :: type conversion to get foo_x86.
So finally I can create my package conversion function by referencing the conversion class like:
template <class type_1>
Packet< typename conversion<type_1>::type > convert(const Packet<type_1>& in) {
Packet< typename conversion<type_1>::type > out;
out.head = convert(in.head);
out.data = convert(in.data);
return out;
}
This allowed the compiler to resolve batch converter references (const Packet & in) just fine without passing template parameters into the call (like the one suggested by da_m_n).
Thanks for all your suggestions!
source to share
I'm not sure I understand your question correctly.
I suggest you change your last "convert" function to:
template<typename Type1, typename Type2>
void convert(const Type1& in, Type2& out)
{
convert(in.quux, out.quux);
}
and one before that:
template <class type_1, class type_2>
void convert(const Packet<type_1>& in, Packet<type_2>& out)
{
out.head = in.head;
convert(in.data, out.data);
}
Finally, define specializations for the main types.
template<>
void convert( const int& in, int& out )
{
out = in;
}
To be tested, but it should work fine.
source to share
Out of curiosity, can conversion constructors be helpful?
struct foo_x86;
struct superfoo_x86;
struct foo {
int bar;
int baz;
explicit foo(const foo_x86& from);
};
struct foo_x86 {
int baz;
int bar;
explicit foo_x86(const foo& from) : bar(from.bar), baz(from.baz) {}
};
foo::foo(const struct foo_x86& from) : bar(from.bar), baz(from.baz) {}
template <class T>
struct Packet {
HeaderType head;
T data;
template <class S>
explicit Packet(const Packet<S>& from) : head(from.head), data(from.data) {}
};
struct superfoo {
Packet<foo> quux;
explicit superfoo(const superfoo_x86& from);
};
struct superfoo_x86 {
Packet<foo_x86> quux;
explicit superfoo_x86(const superfoo& from) : quux(from.quux) {}
};
superfoo::superfoo(const superfoo_x86& from) : quux(from.quux) {}
They seem to have solved the problem with auto-inferring template arguments. You may need to skip specifiers explicit
.
source to share