`std::string::iterator` 保证不是指向 char 的指针吗?

Is `std::string::iterator` guaranteed not to be a pointer to char?

假设 std::ostream 上的 operator<< 重载指向 char 的指针存在,并且假设标准指定了 std::string class 如下,在 §21.4 中:

namespace std {
  template<class charT, class traits = char_traits<charT>,
    class Allocator = allocator<charT> >
  class basic_string {
  public:
    [...]
    typedef implementation-defined iterator;
    typedef implementation-defined const_iterator; 
    [...]
  };
}

最后考虑到 iteratorconst_iteratorContainer 概念的要求是,在 §23.2/4 中:

和指向 char 的指针会满足他们;我是否正确阅读了它的实现定义了以下代码是否编译?

std::string string = "abc";
std::cout << begin(string);

附带说明一下,GCC and Clang 似乎都不接受它。

简答:否

长答案:

这可能取决于您在措辞 "pointer to char" 中输入的内容。它可以被严格解释为正式类型 char* 或类似或更宽松地解释为任何字符所在内存的地址。

我没有看到您提到的重载实际上存在于标准中,但是可能存在其他必需的重载。您作为示例的那个似乎不存在(并且似乎没有任何其他地方有 std::string::iteratorchar* 的重载),例如您不能输出 std::string::iterator 例如:

std::string s = "abc";
std::string.iterator p = s.begin();

std::cout << p; // fails

因为标准说方法和函数应该存在,即使我们要求实现实际上不需要按照标准中指示的方式正式定义它们,而只是表现得好像它是(比较翻译序列的要求)你仍然可能需要区分重载,因为你应该能够将指针指向它们(并且你需要能够知道该指针应该具有什么类型)。

例如,如果我们有一个规范说它应该表现得好像定义了 void foo(long)void foo(int) 并且实现实际上只包含 void foo(long) 只要满足程序只发出对 foo 的函数调用,因为短裤会默默地转换为 int,但是一旦某个程序包含代码以获取指向函数的指针,它就会失败,因为它将存储的类型指针根本不匹配:

 void foo(long);

 foo(1L); // works fine
 foo(1);  // works probably fine, 1 is converted to long first

 void (*f)(int) = foo;  // this fails as it cant convert void(*)(long) to void(*)int

由此我们可以得出结论,std::string::iterator 可能需要是不同的正式类型(如果 char*std::string::iterator 存在重载)。请注意,即使出现 char*char const* 也是一个不同的类型。

然而,如果你只是 "pointer to char" 表示一个字符在内存中的地址(不一定是 char* 类型),那当然可以。人们甚至可以争辩说它很可能是。

std::string 的迭代器的(实际)类型是实现定义的。不要求是指针,也不要求不是指针。

也没有要求标准流具有接受来自任何标准容器(包括 std::string)的迭代器的 operator<<() 变体。反之,没有要求它不得。这意味着 post 末尾的代码是否编译是实现定义的。