Подтвердить что ты не робот

Типовая специализация для всех подклассов

Я хотел бы определить специализацию шаблона С++, которая применяется ко всем подклассам данного базового класса. Это возможно?

В частности, я хотел бы сделать это для STL hash < > . hash < > определяется как пустой параметризованный шаблон и семейство специализаций для определенных типов:

template<class _Key>
  struct hash { };

template<>
  struct hash<char>
  {
    size_t
    operator()(char __x) const
    { return __x; }
  };

template<>
  struct hash<int>
  {
    size_t
    operator()(int __x) const
    { return __x; }
  };
...

Я хотел бы определить что-то вроде этого:

template<class Base>
  struct hash {
    size_t operator()(const Base& b) const {
      return b.my_hash();
    }
  };

class Sub : public Base {
  public:
    size_t my_hash() const { ... }
};

и сможете использовать его следующим образом:

hash_multiset<Sub> set_of_sub;
set_of_sub.insert(sub);

Однако мой хэш-шаблон конфликтует с общим из STL. Есть ли способ (возможно, использование признаков) для определения специализации шаблона, который применяется ко всем подклассам данного базового класса (без изменения определений STL)?

Заметьте, что я знаю, что могу сделать это с некоторыми дополнительными параметрами шаблона всякий раз, когда эта специализация хеширования необходима, но я хотел бы избежать этого, если это возможно:

template<>
  struct hash<Base> {
    size_t operator()(const Base& b) const {
      return b.my_hash();
    }
  };

....

// similar specialization of equal_to is needed here... I'm glossing over that...
hash_multiset<Sub, hash<Base>, equal_to<Base> > set_of_sub;
set_of_sub.insert(sub);
4b9b3361

Ответ 1

Решение состоит в том, чтобы использовать SFINAE для принятия решения о том, разрешить или не разрешить вашу специализацию в зависимости от структуры наследования класса. В Boost вы можете использовать enable_if и is_base_of для реализации этого.

Ответ 2

Это было лучшее, что я мог сделать:

template<>
  struct hash<Sub> : hash<Base> {
  };

Я немного обеспокоен тем, что мне не нужно было делать operator() virtual.