Как я могу определить операции с шаблоном, не заботясь о том, с каким типом он создается? - PullRequest
2 голосов
/ 12 октября 2009

Я унаследовал кучу сетевого кода, который определил множество типов пакетов. Я должен написать набор функций преобразования, которые принимают структуры определенного типа, и копируют значения в другие структуры, которые имеют те же поля, но в другом порядке (как часть замысловатой операции преобразования порядка битов в частичной платформе - don не спрашивайте) Кроме того, я знаю, что могут быть лучшие способы выразить конверсию и т. Д. Ниже, но в данный момент меня это не касается. В частности, я не могу заставить преобразование принимать его выходную переменную по ссылке, потому что я буду передавать битовые поля, и это приведет к ошибке компилятора.

Итак, есть несколько таких структур:

struct foo {
   int bar;
   int baz;
};
struct foo_x86 {
   int baz;
   int bar;
};

И несколько таких функций для преобразования между ними:

foo_x86 convert (const foo & in) { foo_x86 out; out.bar = in.bar; out.baz = in.baz; возвращаться; }

В этом нет ничего страшного. У меня проблема в следующем: есть также структура шаблона, которая выглядит примерно так:

template <class T>
struct Packet {
   HeaderType head;
   T          data;
};

Существует несколько экземпляров этого шаблона, использующих указанные выше типы пакетов в качестве параметров шаблона, например:

struct superfoo {
   Packet<foo> quux;
};
struct superfoo_x86 {
   Packet<foo_x86> quux;
};

Теперь, предполагая, что существует функция foo_x86 convert (const foo &); Есть ли способ создать шаблонную функцию для обработки объектов Packet, которая вызывает эту функцию преобразования?

Например, я хочу что-то, похожее на это:

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;
}

Это будет работать в такой функции, как:

superfoo_x86 convert(const superfoo& in) {
   superfoo_x86 out;
   out.quux = convert(in.quux);
   return out;
}

Я хочу иметь возможность преобразовывать объекты Packet, не обращая внимания на то, с каким типом они создаются, и я хочу избежать необходимости объявлять отдельные функции преобразования для каждого возможного создания экземпляров Packet.

Есть ли какое-либо отношение к шаблонам в C ++?

Ответы [ 4 ]

2 голосов
/ 12 октября 2009

Я не уверен, что правильно понял ваш вопрос.

Я предлагаю вам изменить вашу последнюю функцию "convert" на:

template<typename Type1, typename Type2>
void convert(const Type1& in, Type2& out) 
{
   convert(in.quux, out.quux);
}

и предыдущий:

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);
}

И наконец, определите специализации для фундаментальных типов.

template<>
void convert( const int& in, int& out )
{
  out = in;
}

Будет проверено, но оно должно работать нормально.

1 голос
/ 19 октября 2009

Я закончил тем, что сделал что-то вроде того, что было предложено в комментарии к первоначальному вопросу. Сначала я создал шаблон специализированного класса преобразования, например:

template <class type_1>
struct conversion {};

Затем я добавил макрос для специализации этого класса (который, как я полагаю, похож на шаблон признаков, предложенный нами, верно?), Вот так:

#define GEN_CON(type_1, type_2) \
    template <> struct conversion<type_1> { typedef type_2 type; }

Затем для каждой функции преобразования из foo в foo_x86 я добавил следующий заголовок макроса в заголовок после определения функции преобразования ::

foo_x86 convert (const foo&);
GEN_CON(foo, foo_x86);

Это создает шаблон преобразования для foo и foo_x86, например:

template <>
struct conversion<foo> { typedef foo_x86 type; }

Теперь я могу обратиться к преобразованию :: тип, чтобы получить foo_x86.
Итак, наконец, я могу создать свою функцию преобразования пакетов, ссылаясь на класс преобразования, например:

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;
}

Это позволило компилятору разрешить ссылки на конвертирование пакетов (const Packet & in) просто без необходимости передавать параметры шаблона в вызов (как предложено da_m_n).

Спасибо за все ваши предложения!

0 голосов
/ 12 октября 2009

Из любопытства, были бы полезны конструкторы преобразования?

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) {}

Кажется, они решат проблему с автоматическим определением аргументов шаблона. Возможно, имеет смысл пропустить спецификаторы explicit.

0 голосов
/ 12 октября 2009

Как насчет вызова преобразования, как это?

out.data = convert<type_1, type_2>(in.data);   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...