Я хочу реализовать частичную специализацию для разных итераторов контейнеров. Код компилируется нормально, если я делаю это для контейнеров как таковых, но не работает для их итераторов:
Хорошо
template<typename T>
struct IsContainer : std::false_type {};
template<typename T>
struct IsContainer<std::list<T>> : std::true_type {};
template<typename T>
struct IsContainer<std::set<T>> : std::true_type {};
template<typename T1, typename T2>
struct IsContainer<std::map<T1, T2>> : std::true_type {};
Выдает ошибку:
Class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used
по каждой специализации:
template<typename T>
struct IsIterator : std::false_type {};
template<typename T>
struct IsIterator<std::list<T>::iterator> : std::true_type {};
template<typename T>
struct IsIterator<std::set<T>::iterator> : std::true_type {};
template<typename T1, typename T2>
struct IsIterator<std::map<T1, T2>::iterator> : std::true_type {};
Какова правильная форма для итераторов?
Я не совсем согласен с дубликатами. Они отвечают на вопрос «почему бы и нет», а вопрос здесь скорее о том, «а как иначе?». Также ответ, хотя и отличный, это только половина ответа
Это отвечает на вопрос "тогда как?": stackoverflow.com/a/25292862/5470596
Помимо сложности (или невозможности) вывода параметров: ваш трейт контейнера будет работать только для контейнеров с распределителем по умолчанию. Для итераторов, почему бы просто не использовать iterator_traits вместо специализации для каждого контейнера?
Сообщение компилятора здесь достаточно описательно. Именно так компилятор работает со специализациями шаблонов. Я попытаюсь объяснить, почему это было бы невозможно реализовать с точки зрения компилятора.
Когда у вас есть следующий код:
template<typename T>
struct IsContainer : std::false_type {};
template<typename T>
struct IsContainer<std::list<T>> : std::true_type {};
когда компилятору нужно создать экземпляр IsContainer<SomeType>
, ему нужно проверить, является ли SomeType
std::list
с некоторыми аргументами шаблона или нет, и это вполне выполнимо. Если да - используется частичная специализация, если нет - общая.
Попробуем сделать то же самое для следующего кода:
template<typename T>
struct IsIterator : std::false_type {};
template<typename T>
struct IsIterator<typename std::list<T>::iterator> : std::true_type {};
Если компилятору необходимо создать экземпляр IsContainer<SomeType>
, ему нужно будет проверить, является ли SomeType
std::list<T>::iterator
для некоторого типа T. Поскольку list<T>::iterator
является некоторым независимым типом (теоретически) от list<T>
, единственный вариант сделать это — перечислить все возможные типы (включая бесконечное количество шаблонов). экземпляры), что, очевидно, невозможно.
Я не думаю, что в общем случае так просто решить, является ли что-то итератором или нет. Может быть, вы можете проверить, если есть специализация для
std::iterator_traits<T>