考虑以下课程:
template <class T>
struct X {
T& operator*() & { return t; }
T& operator*() && = delete;
X& operator++() { return *this; }
T t;
};
这个类是否满足C ++标准对Iterator概念的要求? 此类的对象是可递增和可解除引用的。但是禁止取消引用右值对象。
int main() {
X<int> x;
*x; // ok
*X<int>(); // fail. But is it really necessary for Iterator by Standard?
}
答案 0 :(得分:2)
严格阅读标准; [iterator.iterators]/2 (§24.2.2/2)确实提示符合迭代器的类型X
;
...
类型的值a
和b
表示X
或const X
...
r
表示值X&
...如果符合以下条件,
X
类型满足迭代器要求:
- X满足
CopyConstructible
,CopyAssignable
和Destructible
要求([utility.arg.requirements]),类型X
的左值可以交换([swappable.requirements] ])和表(下面)中的表达式是有效的,并具有指示的语义。
*r
(r
可解除引用)++r
(返回X&
)
鉴于代码;
template <class T>
struct X {
T& operator*() & { return t; }
T& operator*() && = delete;
X& operator++() { return *this; }
T t;
};
int main()
{
X<int> x;
++x;
int i = *x;
X<int> y(x);
using std::swap;
std::swap(x, y);
}
当然确实似乎满足了这些要求。
然而,故事仍在继续,上面定义的 Iterator 概念未被列为标准§24.2.1/2中的Iterator类别之一;
本国际标准定义了五类迭代器,根据它们定义的操作:输入迭代器,输出迭代器,前向迭代器,双向迭代器和随机访问迭代器......
它们都定义了X
类型无法编译的操作*a
and *r++
;
int j = *x++; // fails to compile even with the inclusion of the post increment operator
const X<int> xc {};
int ic = *x1; // no const overloads
要使迭代器在一个已定义的类别中可用,它需要包含其他成员,用于取消引用const
值,左值和右值,后增量等。spirit of the standard; < / p>
迭代器是指针的泛化,它允许C ++程序以统一的方式处理不同的数据结构(容器)。
这里对重载成员和运算符的指导是它们可以/应该被添加以强制执行合规并优化(如果可能)广义指针的语义的实现 - 不禁止语义;限制语义可能会产生意想不到的后果。
答案 1 :(得分:1)
嗯,标准没有说明rvalue
引用的迭代器。甚至没有识别其成员因引用类型而重载的迭代器。但是你的代码似乎可以接受为iterator *,因为在定义迭代器的要求时......
引用最新C++14 standard draft的 24.2.2 部分(重点是我的)
24.2.2.2 :如果出现以下情况,则类型X满足迭代器要求:
- X满足 CopyConstructible,CopyAssignable和Destructible要求 类型X的(17.6.3.1)和左值是可交换的(17.6.3.2),并且
- 表106中的表达式是有效的,并具有指示的语义。
* r:r是可解除引用的
++ r:r可递增
除此之外,迭代器没有额外的约束。
*原因,假设结果X<typename ...>
满足第一个列出的条件