满足迭代器需求

Iterator requirements satisfaction

本文关键字:需求 迭代器 满足      更新时间:2023-10-16

考虑以下类:

template <class T>
struct X {
    T& operator*() & { return t; }
    T& operator*() && = delete; 
    X& operator++() { return *this; }
    T t;
};

此类是否满足C++标准对迭代器概念的要求?此类的对象是可增量和可取消引用的。但是禁止取消引用右值对象。

int main() {
    X<int> x;
    *x; // ok
    *X<int>(); // fail. But is it really necessary for Iterator by Standard?
}

严格阅读标准;[iterator.iterators]/2 (§24.2.2/2) 确实暗示了有资格作为迭代器X类型;

ab 表示类型为 Xconst X 的值

r表示值为 X& ...

在以下情况下,类型 X 满足迭代器要求:

  • X 满足 CopyConstructibleCopyAssignableDestructible 要求([utility.arg.requirements]),并且 X 类型的左值是可交换的([swappable.requirements]),并且

  • 表(如下)中的表达式有效,并具有指示的语义。

    • *rr可取消引用)
    • ++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);
}

当然,似乎确实满足了这些要求。

然而,故事还在继续,如上所述的迭代器概念未被列为标准 §24.2.1/2 中的迭代器类别之一;

该国际标准根据对迭代器定义的操作定义了五类迭代器:输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器......

它们都定义了X类型无法编译的操作*a*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值、左值和右值、后增量等。本着标准的精神;

迭代器是指针的泛化,允许C++程序以统一的方式处理不同的数据结构(容器)。

这里对重载成员和运算符的指导是,可以/应该添加它们以强制遵守并优化(如果可能)通用指针语义的实现 - 而不是不允许语义;限制语义可能会产生意想不到的后果。

好吧,该标准没有说明rvalue引用的迭代器。甚至无法识别其成员被其引用类型重载的迭代器。但是您的代码似乎可以接受成为迭代器*,因为在定义迭代器的要求时...

引用最新的 C++14 标准草案第 24.2.2 节(重点是我的)

24.2.2.2: 在以下情况下,X 类型满足迭代器要求:

— X 满足 可复制、可复制可分配和可破坏要求 (17.6.3.1) 和 X 类型的左值可交换 (17.6.3.2),并且

— 表 106 中的表达式是有效的,并且具有指示的语义。

  • *r : r 可取消引用

  • ++r : r 是可递增的

除此之外,迭代器没有额外的约束。


* 原因,假设生成的X<typename ...>满足第一个列出的条件