简体   繁体   English

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

[英]Pattern to specialize templates based on inheritance possible?

So, one problem pattern that I keep coming across and don't have a good solution for is how to provide template specializations that are based in what type a template parameter is derived from. 因此,我一直遇到并且没有一个好的解决方案的一个问题模式是如何提供基于从哪个类型派生模板参数的模板特化。 For example, suppose I have: 例如,假设我有:

template<typename T>
struct implementPersist;

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

What I'd like is for users of persist to be able to provide implementations of implementPersist::persist for types that are declared after the above. 我想要的是,persist的用户能够为上面声明的类型提供implementPersist :: persist的实现。 That's straightforward in principle, but cumbersome in practice but the user need to provide an implementPersist for every type. 原则上这很简单,但在实践中很麻烦,但用户需要为每种类型提供一个implementsPersist。

To be more clear, suppose I have: 更清楚的是,假设我有:

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

My intention is that I provide one template implementation for all subclasses of Persist , another for all subclasses of myBoostPersistedObject and other for miscellaneous classes not in interesting classes structures (eg various POD types). 我的目的是为Persist的所有子类提供一个模板实现,为myBoostPersistedObject的所有子类提供另一个模板实现,为不在有趣的类结构中的其他类提供另一个模板实现(例如,各种POD类型)。 In practice however, 但在实践中,

implementPersist<Persistent>::doPersist

is only ever invoked if ::persist(T&) is called where T is exactly a Persistent object. 只有在调用:: persist(T&)且其中T 恰好Persistent对象时才会调用它。 It falls back to the (missing) generic case where T=myClass. 它回到了(缺失的)通用情况,其中T = myClass。 In general, I want to be able to specialize templates in generic ways based on inheritance. 一般来说,我希望能够基于继承以通用方式专门化模板。 Its little frustrating because clearly compilers know how to do this, and do it when deciding to call functions based upon parameters, eg 它有点令人沮丧,因为显然编译器知道如何做到这一点,并在决定根据参数调用函数时这样做,例如

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

But as far as I can tell, no such similar matching can be done for templates. 但据我所知,模板不能进行类似的匹配。

One workaround is to do something like: 一种解决方法是执行以下操作:

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

(see here for isDerivedFrom). (请参阅此处了解isDerivedFrom)。

However, this requires that the initial declaration of implementPersist knows about the types of the classes providing implementations. 但是,这要求implementPersist的初始声明知道提供实现的类的类型。 I'd like something more generic. 我想要更通用的东西。

I'm frequently finding uses for such a pattern, in order to avoid adding explicit specializations for every class in my system. 我经常发现这种模式的用途,以避免为我的系统中的每个类添加显式特化。

Any ideas? 有任何想法吗?

Yes, you can do this using enable_if. 是的,您可以使用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 has a nicer implementation of enable_if , I just provided it here for completeness. Boost有一个更好的enable_if实现,我只是在这里提供完整性。 Boost also has an example of using it that is very similar to my above example. Boost也有一个使用它的例子,它与我上面的例子非常相似。

Hope that helps. 希望有所帮助。

Try using a reference of the base type to refer to the derived type: 尝试使用基类型的引用来引用派生类型:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM