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 ++?

+2


source to share


4 answers


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!

+1


source


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.

+2


source


How about calling such a transformation?

out.data = convert<type_1, type_2>(in.data);   

      

0


source


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

.

0


source







All Articles