"实例化后std :: iterator_traits <char*>的显式特化"(CLang)

ben*_*wad 2 c++ macos xcode clang template-specialization

我有一些代码可以在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;
};
Run Code Online (Sandbox Code Playgroud)

这是一个namespace std街区.错误消息是:

Explicit specialization of 'std::iterator_traits<char *>' after instantiation
Run Code Online (Sandbox Code Playgroud)

同一错误消息的另一部分(通过'扩展'Xcode中的错误消息查看)说Implicit instantiation first required here,并点击它带我到stl_iterator.h,特别是这一行(第642行):

typedef typename iterator_traits<_Iterator>::iterator_category
                                                         iterator_category;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,有谁知道正确的做法是什么?我见过涉及类的例子,但从来没有涉及结构的例子.

Ada*_*eld 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
};
Run Code Online (Sandbox Code Playgroud)

修复是实例化之前定义特化,因此在此示例中,您将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;
};
Run Code Online (Sandbox Code Playgroud)

并指向constas

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;
};
Run Code Online (Sandbox Code Playgroud)

所以提供自己的std::iterator_traits<char*>专业化是没有意义的.由于char*不是用户定义的类型,因此根据标准,它也是未定义的行为.§17.4.3.1/ 1说:

std除非另有说明,否则C++程序未定义向命名空间中的命名空间std或命名空间添加声明或定义.程序可以将任何标准库模板的模板特化添加到命名空间std.标准库模板的这种特化(完整或部分)会导致未定义的行为,除非声明取决于用户定义的外部链接名称,除非特化符合原始模板的标准库要求.163)

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

  • 我同意@DavidRodríguez-dribeas.更确切地说:17.4.3.1"程序可以将任何标准库模板的模板特化添加到命名空间std.标准库模板的这种特化(完整或部分)会导致未定义的行为,除非声明取决于用户定义的名称外部链接,除非专业化符合原始模板的标准库要求." (2认同)