可以基于继承专门化模板的模式?

时间:2009-05-06 04:49:29

标签: c++ templates

因此,我一直遇到并且没有一个好的解决方案的一个问题模式是如何提供基于从哪个类型派生模板参数的模板特化。 例如,假设我有:

template<typename T>
struct implementPersist;

template<typename T>
void persist( T& object )
{
   implementPersist::doPersist( object );
}

我希望persist的用户能够为上面声明的类型提供implementPersist :: persist的实现。这在原则上很简单,但在实践中很麻烦,但用户需要为每种类型提供一个implementsPersist。

更清楚一点,假设我有:

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&amp;)并且其中T Persistent 对象时,才会调用

。它回到了(缺失的)通用情况,其中T = myClass。一般来说,我希望能够基于继承以通用方式专门化模板。它有点令人沮丧,因为显然编译器知道如何执行此操作,并在决定基于参数调用函数时执行此操作,例如

void persist(Persistent&amp;);    void persist(X&amp;);    void persist(myBoostPersistedObject&amp;);

但据我所知,模板不能进行类似的匹配。

一种解决方法是执行以下操作:

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,请参阅here。)

但是,这要求implementPersist的初始声明知道提供实现的类的类型。我想要更通用的东西。

我经常发现这种模式的用途,以避免为我系统中的每个类添加显式特化。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

是的,您可以使用enable_if。

执行此操作
#include <iostream>
#include <boost/type_traits.hpp>
using namespace std;


template <bool Enable, typename T = void>
struct enable_if
{
    typedef T type;
};

template <typename T>
struct enable_if<false, T>
{
};

template <typename T, typename Enable = void>
struct persist_t {};

struct A
{
    virtual void foo() const = 0;
};

template <typename T>
struct persist_t<T, typename enable_if<boost::is_base_of<A, T>::value>::type>
{
    static void persist(T const& x)
    {
        x.foo();
    }
};


struct B : A
{
    virtual void foo() const { cout << "B::foo\n"; }
};

template <typename T>
void persist(T & x)
{
    persist_t<T>::persist(x);
}

int main()
{
    B b;
    persist(b);
}

Boost有一个更好的enable_if实现,我只是在这里提供完整性。 Boost也有一个使用它的例子,它与我上面的例子非常相似。

希望有所帮助。

答案 1 :(得分:0)

尝试使用基类型的引用来引用派生类型:

MyClass x(...);
Persistent * p = &x;
implementPersist<Persistent> ip;
ip.doPersist(*p);