「这是我参与11月更文挑战的第 8 天,活动详情查看:2021最后一次更文挑战」。
参加该活动的第 17 篇文章
C++11 增加了使用 :
来实现基于 range 的 for 循环新特性,这种循环方式非常简洁直白,它的内部实现是对传统的迭代器 begin()/end()
的遍历做了封装。使用实例代码如下:
/// @note 遍历 vector
std::vector<int> v;
for (auto i : v)
{
cout << i << endl;
}
/// @note 遍历 map
std::map<string, int> map;
for (const auto &item : map) ///< 只读方式
{
cout << item->first << item->second << endl;
}
C++11 基于 range 的 for 循环强大的地方在于它可以支持自定义类型的遍历,但是自定义类型必须满足以下三个条件:
- 要实现
begin()
(返回第一个元素的迭代器) 和end()
(返回最后一个元素的迭代器); - 提供迭代终止的方法;
- 提供遍历 range 的方法;
虽然 C++11 的标准库中有容器如 vector
、list
、queue
、map
、初始化列表和 array
等等都已经支持了基于 range 的 for 循环,但是它们还不够强大,我们的目的,是想构造一个可以根据步长(支持浮点数、字符、正数为前向迭代、负数为反向迭代)生成有序序列的 Range 。
具体实现代码如下:
namespace Cosmos
{
template <typename value_t>
class RangeImpl
{
class Iterator;
public:
RangeImpl(value_t begin, value_t end, value_t step = 1) : m_begin(begin), m_end(end), m_step(step)
{
if (step > 0 && m_begin >= m_end)
throw std::logic_error("end must greater than begin.");
else if (step < 0 && m_begin <= m_end)
throw std::logic_error("end must less than begin.");
m_step_end = (m_end - m_begin) / m_step; ///< 步数
if (m_begin + m_step_end * m_step != m_end)
{
m_step_end++; ///< 补一步
}
}
Iterator begin()
{
return Iterator(0, *this); ///< 返回首元素迭代器
}
Iterator end()
{
return Iterator(m_step_end, *this); ///< 返回末尾元素迭代器
}
value_t operator[](int s) ///< 返回指定索引的值
{
return m_begin + s * m_step;
}
int size()
{
return m_step_end;
}
private:
value_t m_begin;
value_t m_end;
value_t m_step;
int m_step_end;
class Iterator
{
public:
Iterator(int start, RangeImpl &range) : m_current_step(start), m_range(range)
{
m_current_value = m_range.m_begin + m_current_step * m_range.m_step;
}
value_t operator*() { return m_current_value; }
const Iterator *operator++() ///< 正向遍历
{
m_current_value += m_range.m_step;
m_current_step++;
return this;
}
bool operator==(const Iterator &other) ///< 步数是否相同
{
return m_current_step == other.m_current_step;
}
bool operator!=(const Iterator &other) ///< 步数是否不同
{
return m_current_step != other.m_current_step;
}
const Iterator *operator--() ///< 反向遍历
{
m_current_value -= m_range.m_step;
m_current_step--;
return this;
}
private:
value_t m_current_value; ///< 当前值
int m_current_step; ///< 当前步数
RangeImpl &m_range;
};
};
/// @note 三个参数
template <typename T, typename V>
auto Range(T begin, T end, V stepsize) -> RangeImpl<decltype(begin + end + stepsize)>
{
/// @note 类型由 begin/end/stepsize 三者推断
return RangeImpl<decltype(begin + end + stepsize)>(begin, end, stepsize);
}
template <typename T>
RangeImpl<T> Range(T begin, T end) ///< 两个参数
{
return RangeImpl<T>(begin, end, 1); ///< 默认 stepsize = 1
}
template <typename T>
RangeImpl<T> Range(T end) ///< 一个参数
{
return RangeImpl<T>(T(), end, 1); ///< 默认 stepsize = 1
}
}
测试代码如下:
void TestRange()
{
cout << "Range(15):"; ///< 默认从 0 开始的整数
for (int i : Range(15))
{
cout << " " << i;
}
cout << endl;
cout << "Range(2,6):"; ///< begin/end 为整数
for (int i : Range(2, 6))
{
cout << " " << i;
}
cout << endl;
cout << "Range(10.5, 15.5):"; ///< begin/end 为浮点数
for (float i : Range(10.5, 15.5))
{
cout << " " << i;
}
cout << endl;
cout << "Range(35, 27, -1):"; ///< stepsize 为负整数【反向迭代】
for (int i : Range(35, 27, -1))
{
cout << " " << i;
}
cout << endl;
cout << "Range(2, 8, 0.5):"; ///< stepsize 为浮点数
for (float i : Range(2, 8, 0.5))
{
cout << " " << i;
}
cout << endl;
cout << "Range(8, 7, -0.1):"; ///< stepsize 为负浮点数【反向迭代】
for (auto i : Range(8, 7, -0.1))
{
cout << " " << i;
}
cout << endl;
cout << "Range('a', 'z'):"; ///< 遍历字符
for (auto i : Range('a', 'z'))
{
cout << " " << i;
}
cout << endl;
}
输出结果为