"Explicit specialization of std::iterator_traits<char *> after instantiation"(咕)

"Explicit specialization of std::iterator_traits<char *> after instantiation" (CLang)

本文关键字:after gt instantiation char Explicit iterator of traits lt specialization std      更新时间:2023-10-16

我有一些代码在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*定义自己的专门化。您通常只会对不是指针的用户定义迭代器类型执行此操作。参见C++03标准的§24.3.1/2:

[模板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;
};

以及对于作为的指向CCD_ 9的指针

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或命名空间添加声明或定义是未定义的在命名空间std内,除非另有规定。程序可以为任何命名空间CCD_ 13的标准库模板。标准的专门化(完全或部分)库模板会导致未定义的行为,除非声明依赖于的用户定义名称外部链接,除非专业化满足原始模板的标准库要求163)

163)任何实例化其他库模板的库代码都必须准备好与任何用户提供的专业化充分配合符合标准的最低要求