我有一些代码可以在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;
在这种情况下,有谁知道正确的做法是什么?我见过涉及类的例子,但从来没有涉及结构的例子。
答案 0 :(得分:8)
编译器抱怨你在实例化通用模板后试图对模板进行专门化 - 到那个时候,编译器已经使用了通用模板进行实例化,并且它无法返回并使用而你的专业化。换句话说,就像这样:
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; };
指向
的指针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或名称空间添加声明或定义 除非另有说明,否则在
std
命名空间内。程序可以为任何程序添加模板特化 标准库模板到命名空间std
。这种专业化(完全或部分)的标准 库模板导致未定义的行为,除非声明取决于用户定义的名称 外部链接,除非专业化符合原始模板的标准库要求。 163)163)任何实例化其他库模板的库代码都必须准备好与任何用户提供的专业化充分协作 符合标准的最低要求