У меня есть некоторый код, который прекрасно компилируется под MSVC (или, так сказать, разработчиками Windows, которые мне его прислали), но выдает ошибку под CLang. Посмотрев вокруг, я обнаружил, что CLang действительно более строг в разрешении специализаций шаблонов, но я не уверен, куда мне поместить специализации в моем случае. В основном один из моих файлов имеет такую структуру:
template<>
struct iterator_traits< char * > // error is here
{
typedef random_access_iterator_tag iterator_category;
typedef char value_type;
typedef ptrdiff_t difference_type;
typedef difference_type distance_type;
typedef char * pointer;
typedef char & reference;
};
Это в пределах namespace std
блок. Сообщение об ошибке:
Explicit specialization of 'std::iterator_traits<char *>' after instantiation
Другая часть того же самого сообщения об ошибке (просматриваемое «расширением» сообщения об ошибке в XCode) говорит Implicit instantiation first required here
и нажав на это приводит меня к stl_iterator.h
конкретно эта строка (строка 642):
typedef typename iterator_traits<_Iterator>::iterator_category
iterator_category;
Кто-нибудь знает, что делать в этом случае правильно? Я видел примеры с участием классов, но ни разу с использованием структуры.
Компилятор жалуется, что вы пытаетесь специализировать шаблон после создания экземпляра универсального шаблона — к этому моменту компилятор уже использовал универсальный шаблон для создания экземпляра, и он не может вернуться и использовать вашу специализацию вместо этого , Другими словами, что-то вроде этого:
template <typename T>
struct X
{
// Generic implementation
};
// Instantiate template by using it in any way
X<int> foo;
template<>
struct X<int>
{
// Specialization implementation for int
};
Исправление заключается в определении специализации до он создан, поэтому в этом примере вы переместите X<int>
специализация до где раньше X<int>
используется.
Обратите внимание, что STL уже определяет специализации std::iterator_trait
для типов указателей, поэтому нет необходимости определять свою собственную специализацию здесь для char*
, Обычно вы делаете это только для пользовательских типов итераторов, которые не являются указателями. См. § 24.3.1 / 2 стандарта C ++ 03:
[Шаблонiterator_traits<Iterator>
] специализируется на указателях какtemplate<class T> struct iterator_traits<T*> { typedef ptrdiff_t difference_type; typedef T value_type; typedef T* pointer; typedef T& reference; typedef random_access_iterator_tag iterator_category; };
и для указателей на
const
какtemplate<class T> struct iterator_traits<const T*> { typedef ptrdiff_t difference_type; typedef T value_type; typedef const T* pointer; typedef const T& reference; typedef random_access_iterator_tag iterator_category; };
Так что нет смысла предоставлять свои собственные std::iterator_traits<char*>
специализация. поскольку char*
это не определенный пользователем тип, это также неопределенное поведение в соответствии со стандартом. §17.4.3.1 / 1 говорит:
Для программы на C ++ добавление объявлений или определений в пространство имен std или namespace не определено.
в пространстве именstd
если не указано иное. Программа может добавить шаблон специализации для любого
стандартный шаблон библиотеки для пространства именstd
, Такая специализация (полная или частичная) стандарта
шаблон библиотеки приводит к неопределенному поведению, если объявление не зависит от определенного пользователем имени
внешняя связь и если специализация не соответствует стандартным требованиям библиотеки для исходного шаблона.163)163) Любой библиотечный код, который создает экземпляры других библиотечных шаблонов, должен быть подготовлен для адекватной работы с любой предоставленной пользователем специализацией.
соответствует минимальным требованиям стандарта
Других решений пока нет …