更多 C++ 习语/迭代器对
外观
指定一个数据值的范围,而无需担心用于数据值的底层数据结构。
有时这被称为迭代器范围。
众所周知,使用复制构造函数从另一个 vector<int> 创建 vector<int> 是很有用的。类似地,使用应用于成员模板构造函数的 通过成员模板强制转换 习语,从 vector<int> 创建 vector<double> 是很有用的。下面给出了一个代码示例。
template <class T>
class vector
{
public:
vector (const vector<T> &); // copy constructor
template <class U>
vector (const vector<U> &); // constructor using Coercion by Member Template Idiom.
};
vector 接口对于某些需求来说仍然不够灵活。例如,vector 无法从列表或集合或 POD 数组创建自身。
template <class T>
class vector
{
public:
vector (const list<T> &);
// constructor must know the interface of list<T> (not necessarily std::list)
vector (const set<T> &);
// constructor must know the interface of set<T> (not necessarily std::set)
vector (const T * pod_array);
// another constructor - does not know where pod_array ends - too inflexible!
};
迭代器对是一种解决此挑战的习语。它基于迭代器设计模式(显然!)。迭代器模式的意图:提供一个遍历某些聚合结构的对象,抽象出对该结构实现的假设。
一对迭代器用于指定一个值的范围的开始和结束。凭借迭代器设计模式,无论是谁(在我们的示例向量中)使用迭代器对习语,都可以访问范围而无需担心聚合数据结构的实现。唯一的要求是迭代器应该公开一个固定的、最小的接口,例如前增量运算符。
template <class T>
class vector
{
T * mem;
public:
template <class InputIterator>
vector (InputIterator begin, InputIterator end) // Iterator-pair constructor
{
// allocate enough memory and store in mem.
mem=new T[std::distance(begin, end)];
for (int i = 0; begin != end; ++i)
{
mem[i] = *begin;
++begin;
}
}
};
int main (void)
{
std::list<int> l(4);
std::fill(l.begin(),l.end(), 10); // fill up list using iterator pair technique.
std::set<int> s(4);
std::fill(s.begin(),s.end(), 20); // fill up set using iterator pair technique.
std::vector<int> v1(l.begin(), l.end()); // create vector using iterator pair technique.
std::vector<int> v2(s.begin(), s.end()); // create another vector.
}
迭代器对习语通常与成员模板结合使用,因为迭代器的确切类型不是先验知道的。它可以是 set<T>::iterator 或 list<T>::iterator 或 POD 数组。无论类型如何,以迭代器对表示的任何通用算法都可以工作。通常使用说明迭代器类型应该建模的概念很有用。在上面的示例中,迭代器至少需要建模 InputIterator 概念。有关迭代器类别(标签)及其用法的更多信息,请参见标签分派习语。
有时迭代器对习语是不可避免的。例如,要从带有嵌入空字符的字符缓冲区构造一个 std::string,迭代器对习语是不可避免的。
char buf[] = { 'A', 'B', 0, 'C', 0, 'D'};
std::string str1 (buf); // only creates "AB"
std::string str2 (buf, buf + sizeof (buf) / sizeof (*buf)); // Using iterator pair. Creates "AB_C_D"
// buf is start of the range and buf + sizeof (buf) / sizeof (*buf) is the end of the range.
std::cout << str1 << " length = " << str1.length() << std::endl; // AB length = 2
std::cout << str2 << " length = " << str2.length() << std::endl; // AB_C_D length = 6
所有标准容器