Template specialization based on inherit class

后端 未结 4 1899
忘掉有多难
忘掉有多难 2020-12-01 03:39

I want to make this specialized w/o changing main. Is it possible to specialize something based on its base class? I hope so.

-edit-

I\'ll have several class

相关标签:
4条回答
  • 2020-12-01 04:21

    This article describes a neat trick: http://www.gotw.ca/publications/mxc++-item-4.htm

    Here's the basic idea. You first need an IsDerivedFrom class (this provides runtime and compile-time checking):

    template<typename D, typename B>
    class IsDerivedFrom
    {
      class No { };
      class Yes { No no[3]; }; 
    
      static Yes Test( B* ); // not defined
      static No Test( ... ); // not defined 
    
      static void Constraints(D* p) { B* pb = p; pb = p; } 
    
    public:
      enum { Is = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) }; 
    
      IsDerivedFrom() { void(*p)(D*) = Constraints; }
    };
    

    Then your MyClass needs an implementation that's potentially specialized:

    template<typename T, int>
    class MyClassImpl
    {
      // general case: T is not derived from SomeTag
    }; 
    
    template<typename T>
    class MyClassImpl<T, 1>
    {
      // T is derived from SomeTag
      public:
         typedef int isSpecialized;
    }; 
    

    and MyClass actually looks like:

    template<typename T>
    class MyClass: public MyClassImpl<T, IsDerivedFrom<T, SomeTag>::Is>
    {
    };
    

    Then your main will be fine the way it is:

    int main()
    {
        MyClass<SomeTag>::isSpecialized test1; //ok
        MyClass<InheritSomeTag>::isSpecialized test2; //ok also
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-01 04:24

    Well, the article in the answer above appeared in February 2002. While it works, today we know there are better ways. Alternatively, you can use enable_if:

    template<bool C, typename T = void>
    struct enable_if {
      typedef T type;
    };
    
    template<typename T>
    struct enable_if<false, T> { };
    
    template<typename, typename>
    struct is_same {
        static bool const value = false;
    };
    
    template<typename A>
    struct is_same<A, A> {
        static bool const value = true;
    };
    
    template<typename B, typename D>                                 
    struct is_base_of {                                                       
        static D * create_d();                     
        static char (& chk(B *))[1]; 
        static char (& chk(...))[2];           
        static bool const value = sizeof chk(create_d()) == 1 &&  
                                  !is_same<B    volatile const, 
                                           void volatile const>::value;
    };
    
    struct SomeTag { };
    struct InheritSomeTag : SomeTag { };
    
    template<typename T, typename = void>
    struct MyClass { /* T not derived from SomeTag */ };
    
    template<typename T>
    struct MyClass<T, typename enable_if<is_base_of<SomeTag, T>::value>::type> {
        typedef int isSpecialized;
    };
    
    int main() {
        MyClass<SomeTag>::isSpecialized test1;        /* ok */
        MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
    }
    
    0 讨论(0)
  • 2020-12-01 04:25

    And the short version now, 2014, using C++-11:

    #include <type_traits>
    
    struct SomeTag { };
    struct InheritSomeTag : SomeTag { };
    
    template<typename T, bool = std::is_base_of<SomeTag, T>::value>
    struct MyClass { };
    
    template<typename T>
    struct MyClass<T, true> {
        typedef int isSpecialized;
    };
    
    int main() {
        MyClass<SomeTag>::isSpecialized test1;        /* ok */
        MyClass<InheritSomeTag>::isSpecialized test2; /* ok */
    }
    
    0 讨论(0)
  • 2020-12-01 04:37

    In your case, the only way that I see would be to explicitly specialize MyClass for InheritSomeTag. However, the SeqAn paper proposes a mechanism called “template sublassing” that does what you want – albeit with a different inheritance syntax, so the code isn't compatible with your current main function.

    // Base class
    template <typename TSpec = void>
    class SomeTag { };
    
    // Type tag, NOT part of the inheritance chain
    template <typename TSpec = void>
    struct InheritSomeTag { };
    
    // Derived class, uses type tag
    template <typename TSpec>
    class SomeTag<InheritSomeTag<TSpec> > : public SomeTag<void> { };
    
    template <class T, class Tag=T>
    struct MyClass { };
    
    template <class T, typename TSpec>
    struct MyClass<T, SomeTag<TSpec> >
    {
        typedef int isSpecialized;
    };
    
    int main()
    {
        MyClass<SomeTag<> >::isSpecialized test1; //ok
        MyClass<SomeTag<InheritSomeTag<> > >::isSpecialized test2; //ok
    }
    

    This certainly looks strange and is very cumbersome but it allows a true inheritance mechanism with polymorphic functions that is executed at compile time. If you want to see this in action, have a look at some SeqAn examples.

    That being said, I believe that SeqAn is a special case and not many applications would profit from this extremely difficult syntax (deciphering SeqAn-related compiler errors is a real pain in the *ss!)

    0 讨论(0)
提交回复
热议问题