C++20 迭代器是否可“转换”为传统迭代器?

4

我理解,在C++20之前,迭代器只是由标准定义的一种概念。现在在C++20中,它们成为了真正的语言概念,并在编译时进行检查。我想知道我是否可以安全地假设我可以在我的API中使用C++20迭代器并将其传递给任何早于C++20的API而不会出现问题:

演示

#include <string>
#include <concepts>
#include <cstdio>
#include <utility>

auto write_string(std::input_iterator auto it) -> void { // <-- C++20 iterator

    std::string ret = "Danger";
    std::copy(ret.begin(), ret.end(), it); // <-- requires LegacyInputIterator
}

int main()
{
    std::string str = "Austin is my middle name";
    write_string(str.begin());
    printf("%.*s\n", (int)str.size(), str.data());
}

@康桓瑋,那么最好的方法是什么呢?是将 std::copy 使用的基础迭代器概念转发到我的 API 吗? - glades
1
概念是一种检查类型是否符合要求的花哨方式。实际类型仍然相同。decltype(it)decltype(str.begin())将产生相同的类型(忽略值类别)。它们不是“可转换的”,它们是同一件事情。 - Yksisarvinen
@Yksisarvinen True 应该使用来自不同实体的输入迭代器,但我想不到一个(如果您有更一般的示例,请考虑编辑问题)。关键是这个API将接受满足c++20输入迭代器类别的所有迭代器。如何将其约束为std :: copy使用的迭代器,以获得更狭窄的匹配? - glades
@康桓瑋,这个源代码似乎表明,当我使用C++20时,实际上应该使用这些概念来约束迭代器(请参见指南)... - glades
我并不确定您在这里的问题是什么。如果传递了错误的迭代器,它无论如何都不能编译(可能会带有更加神秘的错误消息)。std::vector<int> v{}; write_string(v.begin());无论是否使用概念,都将无法编译。您可以接受 std::string::iterator 作为参数,但这会阻止 std::vector<char>::iterator 的传递。如果您想要一个检查此特定“复制”是否可以被调用的概念,您可以设计自己的概念来检查该类型是否为 std::output_iterator 并且 std::is_same_v<*it, char>。但我认为这有点过头了。 - Yksisarvinen
2个回答

3

std::copy 要求第三个参数的类型必须满足 LegacyOutputIterator 的要求,也就是说,它必须支持写操作,而这并不被 std::input_iterator 保证。

在 C++20 中,相应的概念是 std::output_iterator,因此您可以将 write_string 重新声明为

void write_string(std::output_iterator<const char&> auto it) {
  std::string ret = "Danger";
  std::copy(ret.begin(), ret.end(), it);
}

这将确保it的类型满足写入char输出迭代器的语法要求。

(虽然C++20的迭代器系统与C++98/C++17非常不同,但输出迭代器的要求基本上是等价的。因此,在您的示例中,使用std::output_iterator来检查LegacyOutputIterator的要求是可以的)


1

不。

旧的LegacyInputIterator概念还需要std::equality_comparable,但对于std::input_iterator不再需要。

因此,一个不是std::equality_comparable的C++20迭代器类型不是LegacyInputIterator,可能会破坏旧的API。

然而,std::output_iterator不需要是std::equality_comparable


在哪里需要LegacyIteratorequality_comparable?Cppreference没有提到LegacyIterator需要,而明确提到LegacyOutputIterator不需要可比性。 - Yksisarvinen
@Bob__ 啊,对了。有点混淆的是,OP选择谈论std::input_iterator作为应该是LegacyOutputIterator的参数。我会自行编辑答案,将LegacyIterator更改为LegacyInputIterator - Yksisarvinen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接