Итак, одна проблема, с которой я постоянно сталкиваюсь и для которой нет хорошего решения, - это как обеспечить специализации шаблона, основанные на том, из какого типа получен параметр шаблона.
Например, предположим, у меня есть:
template<typename T>
struct implementPersist;
template<typename T>
void persist( T& object )
{
implementPersist::doPersist( object );
}
Что бы я хотел, чтобы пользователи persist могли предоставлять реализации Implementers :: persist для типов, которые объявлены после вышеперечисленного. Это просто в принципе, но на практике громоздко, но пользователю необходимо предоставить внедряемый список для каждого типа.
Для большей ясности предположим, что у меня есть:
struct Persistent { virtual void myPersist() = 0; };
struct MyClass : public persistent { virtual void MyPersist() { ...implementation...} };
// Persists subclasses of Persistent using myPersist
template<>
struct implementPersist<Persistent>{ void doPersist(Persistent& p) { p->myPersist(); } };
struct X{};
template<>
struct implementPersist<X>{ void doPersist(X& p) { ...implementation...} };
// Persists subclasses of Persistent using boostPersist
struct MyBoostPersistedObject { virtual void boostPersist() = 0 };
struct Z : public MyBoostPersistedObject { virtual void boostPersist() = 0 };
template<>
struct implementPersist<myBoostPersistedObject>{ void boostPersist() { ...implementation... } };
Я намерен предоставить одну реализацию шаблона для всех подклассов Persist , другую для всех подклассов myBoostPersistedObject и другую для разных классов, не входящих в структуры интересных классов (например, различные типы POD).
Однако на практике
implementPersist<Persistent>::doPersist
вызывается только в том случае, если :: persist (T &) вызывается, когда T является точно a Постоянным объектом. Это возвращается к (отсутствующему) общему случаю, когда T = myClass. В общем, я хочу иметь возможность специализировать шаблоны на общих принципах, основанных на наследовании. Это немного расстраивает, потому что компиляторы четко знают, как это сделать, и делают это при принятии решения о вызове функций на основе параметров, например,
void persist (Постоянный &);
пустота сохраняется (X &);
void persist (myBoostPersistedObject &);
Но, насколько я могу судить, подобное сопоставление не может быть выполнено для шаблонов.
Один из обходных путей - сделать что-то вроде:
class persist;
template<typename T, bool hasMyPersistMethod=isDerivedFrom(T,persist)::value >
struct implementPersist;
template<typename T, bool true >
struct implementPersist<T,true>
{
template<> struct implementPersist<X>{ void doPersist(T& p) { p->myPersist(); } }
};
(см. здесь для isDerivedFrom).
Однако для этого необходимо, чтобы первоначальное объявление Implementers знало о типах классов, обеспечивающих реализации. Я хотел бы что-то более общее.
Я часто нахожу применение для такого шаблона, чтобы избежать добавления явных специализаций для каждого класса в моей системе.
Есть идеи?