Условно специализировать std :: ha sh для структуры std :: shared_ptr - PullRequest
0 голосов
/ 10 апреля 2020

У меня есть базовый базовый класс. Цель состоит в том, чтобы заставить специализовать std :: ha sh для std :: shared_ptr со всеми классами, которые наследуются от Base.

Я пробовал следующий подход с фиктивным параметром шаблона, но ошибка компилятора, очевидно, жалуется что это переопределение struct std::hash<std::shared_ptr<_Tp>>.

class Base {
};

class Derived : public Base {
};

namespace std {

template<typename T,
         typename std::enable_if<std::is_base_of<Base, T>::value, Base>::type* = nullptr
>
struct hash<std::shared_ptr<T>> {    
    size_t operator()(const std::shared_ptr<T>& d) const {
        return 616;
    }
};
}

Мой вопрос: возможно ли условно специализировать класс std как этот?

1 Ответ

1 голос
/ 10 апреля 2020

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

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

#include <memory>
#include <utility>

class Base {};

class Derived : public Base {};

template <typename First, typename... Others>
using first = First;

namespace std {

template <typename T>
struct hash<first<std::shared_ptr<T>,
                  std::enable_if_t<std::is_base_of_v<Base, T>>>> {
  size_t operator()(const std::shared_ptr<T>& d) const { return 616; }
};

}  // namespace std

что, я бы предположил, в принципе нормально, потому что объявление зависит от определяемого пользователем типа Base.

В стандарте существует нерешенная проблема относительно того, следует ли считать эту специализацию переопределением стандарта. специализация для std::shared_ptr. (G CC считает, что это не так, Clang думает, что это так.)

Но что более важно, тогда у вас все еще есть проблема, что эта частичная специализация не более специализирована, чем та, которую стандарт предусматривает std::shared_ptr. Поэтому любое фактическое использование может привести к ошибке неоднозначности, и я не думаю, что есть какой-либо способ сделать специализацию более специализированной.

Таким образом, я думаю, что ваше единственное решение - это определить явную специализацию для std::hash для каждый производный тип, может быть, с помощью макроса. Или, в качестве альтернативы (и, возможно, более уместно), вы должны написать свой собственный хеш-функтор и указать его в качестве альтернативы std::hash там, где это необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...