【问题标题】:How to partially specialize a class template for all derived types?如何为所有派生类型部分专门化一个类模板?
【发布时间】:2010-11-05 04:49:30
【问题描述】:

我想为基类和所有派生类部分专门化我无法更改的现有模板 (std::tr1::hash)。原因是我使用奇怪重复的模板模式来实现多态性,并且哈希函数是在 CRTP 基类中实现的。如果我只想部分专门针对 CRTP 基类,那很简单,我可以写:


namespace std { namespace tr1 {

template <typename Derived>
struct hash<CRTPBase<Derived> >
{
    size_t operator()(const CRTPBase<Derived> & base) const 
    { 
        return base.hash(); 
    }
};

} }

但是这种特化与实际的派生类不匹配,只匹配CRTPBase&lt;Derived&gt;。我想要的是一种为Derived 编写部分专业化的方法,当且仅当它派生自CRTPBase&lt;Derived&gt;。我的伪代码是


namespace std { namespace tr1 {

template <typename Derived>
struct hash<typename boost::enable_if<std::tr1::is_base_of<CRTPBase<Derived>, Derived>,
    Derived>::type>
{
    size_t operator()(const CRTPBase<Derived> & base) const 
    { 
        return base.hash(); 
    }
};

} }

...但这不起作用,因为编译器无法判断enable_if&lt;condition, Derived&gt;::typeDerived。如果我可以更改std::tr1::hash,我会按照enable_if 文档的建议添加另一个虚拟模板参数以使用boost::enable_if,但这显然不是一个很好的解决方案。有没有办法解决这个问题?我是否必须在我创建的每个 unordered_setunordered_map 上指定自定义哈希模板,或者为每个派生类完全专门化 hash

【问题讨论】:

    标签: c++ derived-class partial-specialization crtp


    【解决方案1】:

    以下代码有两种变体。你可以选择更适合你的。

    
    template <typename Derived>
    struct CRTPBase
    {
        size_t hash() const {return 0; }
    };
    
    // First case 
    //
    // Help classes
    struct DummyF1 {};
    struct DummyF2 {};
    struct DummyF3 {};
    template<typename T> struct X; 
    
    // Main classes
    template<> struct X<DummyF1> : CRTPBase< X<DummyF1> > {
        int a1;
    };
    
    template<> struct X<DummyF2> : CRTPBase< X<DummyF2> > {
        int b1;
    };
    
    // typedefs
    typedef X<DummyF1> F1;
    typedef X<DummyF2> F2;
    typedef DummyF3    F3; // Does not work
    
    namespace std { namespace tr1 {
        template<class T>
        struct hash< X<T> > {
            size_t operator()(const CRTPBase< X<T> > & base) const     
            {         
                return base.hash();     
            }
        };
    }} // namespace tr1 // namespace std 
    
    //
    
    // Second case
    struct DummyS1 : CRTPBase <DummyS1> {
        int m1;
    };
    //
    template<typename T> 
    struct Y : T {};
    //
    typedef Y<DummyS1> S1;
    
    
    namespace std { namespace tr1 {
        template<class T>
        struct hash< Y<T> > {
            size_t operator()(const CRTPBase<T> & base) const     
            {         
                return base.hash();     
            }
        };
    }} // namespace tr1 // namespace std 
    
    void main1()
    {
        using std::tr1::hash;
        F1 f1;
        F2 f2;
        F3 f3;
        hash<F1> hf1; size_t v1 = hf1(f1); // custom hash functor
        hash<F2> hf2; size_t v2 = hf2(f2); // custom hash functor
        hash<F3> hf3; size_t v3 = hf3(f3); // error: standard hash functor
    
        S1 s1;
        hash<S1> hs1; size_t w1 = hs1(s1); // custom hash functor
    
    }
    

    【讨论】:

      【解决方案2】:

      您应该创建自己的命名空间并在其中定义新结构 hash,而不是修改 std::tr1::hash,它继承自 std::tr1::hash 或专门用于 CRTPBase&lt;Derived&gt;

      
      template <typename Derived>
      struct CRTPBase
      {
          size_t hash() {return 0; }
      };
      
      struct AA : CRTPBase <AA> {};
      struct BB {};
      //
      namespace mynamespace {
      
      template <typename Some, typename Dummy=char> 
      struct hash : std::tr1::hash<Some> {};
      //
      template <typename Derived>
      struct hash<Derived, 
        typename boost::enable_if< std::tr1::is_base_of<CRTPBase<Derived>, Derived>, char>::type >
      {    
          size_t operator()(const CRTPBase<Derived> & base) const     
          {         
              return base.hash();     
          }
      };
      
      } // namespace mynamespace {}
      //
      //
      void ff()
      {
          using namespace mynamespace;
      
          hash<AA> aa;  // my hash
          hash<BB> bb;  // std::tr1::hash
      
      }
      

      【讨论】:

      • 但是他仍然必须在每个 unordered_set 上指定一个自定义哈希模板,因为它不会使用他的命名空间。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-06
      • 1970-01-01
      相关资源
      最近更新 更多