C++ 容器begin/end/cbegin/cend语义、迭代器/常量迭代器兼容性

C++ 容器begin/end/cbegin/cend语义、迭代器/常量迭代器兼容性,c++,iterator,containers,c++17,const-correctness,C++,Iterator,Containers,C++17,Const Correctness,我一直在开发一个定制的ReversibleContainer,我认为我走上了正确的道路,但在测试过程中遇到了一个障碍,因为我正在研究的语义使我认为我基本上错误地实现了这一点。我正在使用C++17 特别是,我当前的实现有点像这样(请原谅错误,我在这里键入时将其压缩为一个示例),其中: 项是容器的类型 元素是迭代器解除引用的类型(可转换为项) struct用于此代码段中的整体简洁性 只包括我认为相关的类型和成员 struct my\u容器{ 使用值\类型=项目; 使用引用=值\类型&; 使用co

我一直在开发一个定制的ReversibleContainer,我认为我走上了正确的道路,但在测试过程中遇到了一个障碍,因为我正在研究的语义使我认为我基本上错误地实现了这一点。我正在使用C++17

特别是,我当前的实现有点像这样(请原谅错误,我在这里键入时将其压缩为一个示例),其中:

  • 是容器的类型
  • 元素
    是迭代器解除引用的类型(可转换为
  • struct
    用于此代码段中的整体简洁性
  • 只包括我认为相关的类型和成员
struct my\u容器{
使用值\类型=项目;
使用引用=值\类型&;
使用const_reference=const value_type&;
使用size\u type=std::vector::size\u type;
使用差分类型=标准::向量::差分类型;
结构元素{
// ... 
};
//V是值类型,D是正向/反向迭代器控件的一部分
模板结构迭代器{
使用迭代器\u category=std::随机访问\u迭代器\u标记;
使用值_type=V;
使用reference=V&;
使用指针=V*;
使用差异类型=我的容器::差异类型;
迭代器();//自定义
迭代器&(常量迭代器&)=默认值;
迭代器&(迭代器&&)=默认值;
~iterator_uz()=默认值;
迭代器&&运算符=(常量迭代器&)=默认值;
迭代器&&运算符=(迭代器&&)=默认值;
布尔运算符==(常量迭代器&)常量;
// ...
};
使用迭代器=迭代器;
使用常量迭代器=迭代器;
使用反向迭代器=迭代器;
使用常量反迭代器=迭代器;
迭代器begin();
迭代器end();
常量迭代器cbegin()常量;
常量迭代器cend()常量;
反向迭代器rbegin();
反向迭代器rend();
const_reverse_迭代器crbegin()const;
const_reverse_迭代器crend()const;
};
现在,我正在研究
begin
end
cbegin
cend
的操作语义(其中
a
my_容器
,而
C
是它的类型):

表达 返回类型 语义学
a.begin()
(常数)迭代器 迭代到
a的第一个元素
a.end()
(常数)迭代器 迭代器到
a
a.cbegin()
常量迭代器
const\u cast(a).begin()
a.cend()
常量迭代器
const\u cast(a).end()
是的,
const_iterator it=iterator
应该可以工作(但不是相反),就像
==
一样(我不确定第一个是强制的,但您仍然应该这样做)

还考虑编写可怕的迭代器,其中迭代器不是容器的子类型。

template<class T>
struct foo {
   template<class U, std::enable_if_t<std::is_same_v<std::remove_cv_t<U>, std::remove_cv_t<T>>,bool> =true>
   friend bool operator==( foo const& lhs, foo<U> const& rhs );
};
模板
结构foo{
模板
友元布尔运算符==(foo-const&lhs,foo-const&rhs);
};

这是一个在不同类型之间工作的
=
示例。

打开更好的标题,这个有点粗糙…
迭代器
应该可以转换为
常量迭代器
。它们可以是不相关的类型,但是它们必须显式地提供合适的转换—转换构造函数或转换运算符。当调用
const
容器时,您的
begin
end
确实会返回
const\u迭代器
。您可以声明
const\u迭代器begin()const无论如何,在你走得太远之前-我不相信代理迭代器(迭代器,其中
操作符*
返回的不是对容器值类型的引用)满足迭代器的要求。这就是为什么
std::vector
不是一个合适的容器的主要原因。你说“
元素
是类型迭代器解除引用(它可以转换为
)”-这听起来像是代理迭代器。@JasonC作为你正在使用的内容的副本,它们可能应该是
cbegin
cend
,但作为你应该使用的内容的副本,打字实际上是正确的。;)免费提示:尝试将容器需求的实现与标准容器进行比较,看看它们是否不同。如果选择
std::vector
,则可能意味着将您的成员函数与进行比较。只关注适用于所选方言(C++17)的三个声明;添加
const
begin
end
的定义似乎可以使容器端的一切更加一致。现在我只需要研究迭代器的兼容性。我想我可以在
迭代器
中添加一个
常量迭代器
转换运算符,然后编写全局比较运算符,以获取
常量迭代器
s。Re:
=
和其他人我在那里发现了一个脚注,上面写着“给定的
迭代器
I和j,在表达式I==j,I=j,Ij,I-j中,其中一个或两个都可以被容器的……const_迭代器类型的对象替换……语义没有变化。”这使我相信所有的比较都需要两者兼而有之。或者至少,这是我将如何使它工作,似乎是一个好主意。谢谢。不,迭代器不能转换为from const迭代器;这违反了const correction@jason的精神,相反!嗯,<代码>迭代器::运算符常量迭代器()常量,这就是我的意思。天哪,老兄,我可能累了,但我没有疯
iterator begin ();
iterator end ();
const_iterator begin () const;
const_iterator end () const;
const_iterator cbegin () const;
const_iterator cend () const;
template<class T>
struct foo {
   template<class U, std::enable_if_t<std::is_same_v<std::remove_cv_t<U>, std::remove_cv_t<T>>,bool> =true>
   friend bool operator==( foo const& lhs, foo<U> const& rhs );
};