2015-06-09 2 views
2

Я работаю с некоторым неудачным кодом, который имеет два совершенно разных механизма сериализации. Один использует шаблон для архива, который выглядит как template <class Archive> void serialize_v1(Archive& a), а другой использует template <template <bool> class Archive> void serialize_v2(Archive<false>& a). Первый перегружает оператор для сериализации типа a % foo для сериализации, а второй использует методы в архиве, такие как a.proc_int(foo).Можно ли создать шаблон, который при специализировании дает другой шаблон?

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

template <class ArchiveV1> 
class serialize_adapter 
{ 
    serialize_adapter(ArchiveV1& one) : one(one) { }; 

    // functions for v2 serialization 
    void proc_int(int x) { 
     one % x; 
    } 

    ArchiveV1& one; 
} 

template <class ArchiveV1> 
void serialize_v1(ArchiveV1& one) 
{ 
    serialize_v2(serialize_adapter(one)); // calls adapter's v2 funcs 
} 

Однако serialize_v2 принимает template <bool> class ArchiveV2, который serialize_adapter(one) не соответствует - так это просто class ArchiveV1. Но serialize_adapter не может просто взять bool - он должен принять параметр ArchiveV1.

Похоже, мне нужно создать шаблон, который специализируется на типе Archive, что приводит к шаблону, который специализируется на bool, который я могу передать на serialize_v2. Как я могу это сделать, или какой правильный подход, если это неправильный подход?

ответ

1

template <bool> class ArchiveV2 можно увидеть как metafunction S: bool -> type. То, что вам нужно, можно рассматривать как метафокус A: type -> S, то есть «метаметанную функцию». Metafunction, который возвращает metafunction можно записать с помощью шаблона члена:

template<class ArchiveV1> 
struct serialize_adapter 
{ 
    template<bool> 
    struct result 
    { 
     void proc_int(int x) { 
      one % x; 
     } 

     ArchiveV1& one; 
    }; 
}; 

Примечания аналогии с "обычной" метафункцией:

template<class X> 
struct metafun 
{ 
    using result = /* some type */; 
}; 

(result часто называют type)

Адаптером функцию можно записать в виде:

template <class ArchiveV1> 
void serialize_v1(ArchiveV1& one) 
{ 
    using adapter = serialize_adapter<ArchiveV1>::template result<false>; 
    serialize_v2(adapter{one}); // calls adapter's v2 funcs 
} 
+0

Если вам нужно больше этих классов адаптеров, вы также можете ввести фиктивный bool через наследование + CRTP. – dyp

0

Сделайте это наоборот: напишите serialize_adaptor, который принимает более специализированный тип - это класс, который проистекает из шаблона с логическим параметром, - и превращает его в общий.

Пример:

template <template<bool> class ArchiveV2> 
class serialize_adapter 
{ 
    serialize_adapter(ArchiveV2<false>& one) : one(one) { }; 

    // functions for v1 serialization 
    void operator%(int x) { 
     one.proc_int(x); 
    } 

    ArchiveV2<false>& one; 
} 

template <template<typename> class ArchiveV2> 
void serialize_v2(ArchiveV2<false>& one) 
{ 
    serialize_v1(serialize_adapter(one)); // calls adapter's v1 funcs 
} 

Здесь, вероятно, следует добавить некоторые дополнительные специализации для случая, когда логический параметр true.

Смежные вопросы