芝兰生于深谷,不以无人而不芳
君子修身养德,不以穷困而改志
标准库容器范围for
vector
std::vector<int> vec{1, 1, 2, 3, 5, 8, 13};
for (auto v : vec) {
std::cout << v << " ";
}
// output: 1 1 2 3 5 8 13
map
std::map<int, bool> items{{1, true}, {2, false}, {3, true}};
for (auto item : items) {
std::cout << "(" << item.first << ", " << item.second << ") ";
}
// output: (1, 1) (2, 0) (3, 1)
c++17可以使用结构化绑定的方式
for (auto [key, value] : items) {
std::cout << "(" << key << ", " << value << ") ";
}
// output: (1, 1) (2, 0) (3, 1)
自定义类型
为了展示如何为自定义类型可以使用范围for循环,我们以下面的简单数组的实现为例说明
template<typename T, size_t const Size>
struct dummy_array {
T const& get_at(size_t const index) const {
if (index < Size) return data[index];
throw std::out_of_range("index out of range");
}
void set_at(size_t const index, T const& value) {
if (index < Size) data[index] = value;
else throw std::out_of_range("index out of range");
}
size_t size() const { return Size; }
private:
T data[Size] = {};
};
我们需要如何让下面的代码通过
dummy_array<int, 3> arr;
arr.set_at(0, 1);
arr.set_at(1, 2);
arr.set_at(2, 3);
for (auto&& e : arr) { // 编译错误
std::cout << e << '\n';
}
How to do it
为了完成上述的操作,我们需要完成两件事情
创建可变和常量迭代器
• operator++(包括前缀和后缀版本)用于递增迭代器
• operator* 用于解引用迭代器并访问迭代器指向的实际元素
• operator!= 用于与另一个迭代器进行比较
以上面的dummy_array为例,我们先实现它的迭代器
template<typename T, typename C, size_t const Size>
struct dummy_array_iterator_type {
dummy_array_iterator_type(C& collection, size_t const index)
: index(index), collection(collection) {}
bool operator!=(dummy_array_iterator_type const& other) const {
return index != other.index;
}
T const& operator*() const {
return collection.GetAt(index);
}
dummy_array_iterator_type& operator++() {
++index;
return *this;
}
dummy_array_iterator_type operator++(int) {
auto temp = *this;
++*temp;
return temp;
}
private:
size_t index;
C& collection;
};
声明别名模板,mutable和const类型都需要声明
template<typename T, size_t const Size>
using dummy_array_iterator = dummy_array_iterator_type<T, dummy_array<T, Size>, Size>;
template<typename T, size_t const Size>
using dummy_array_const_iterator = dummy_array_iterator_type<T, dummy_array<T, Size> const, Size>;
提供begin() 和 end() 的自由函数
begin() 和 end() 函数返回相应的开始和结束迭代器,上面两个别名模板都需要有重载:
template<typename T, size_t const Size>
inline dummy_array_iterator<T, Size> begin(dummy_array<T, Size>& collection) {
return dummy_array_iterator<T, Size>(collection, 0);
}
template<typename T, size_t const Size>
inline dummy_array_iterator<T, Size> end(dummy_array<T, Size>& collection) {
return dummy_array_iterator<T, Size>(collection, collection.GetSize());
}
template<typename T, size_t const Size>
inline dummy_array_const_iterator<T, Size> begin(dummy_array<T, Size> const& collection) {
return dummy_array_const_iterator<T, Size>(collection, 0);
}
template<typename T, size_t const Size>
inline dummy_array_const_iterator<T, Size> end(dummy_array<T, Size> const& collection) {
return dummy_array_const_iterator<T, Size>(collection, collection.GetSize());
}
begin() 和 end() 函数对于这两种类型的迭代器都有两个重载,是为了常量和非常量实例的都可以使用范围 for 循环。