【C++11】理解基于范围的for循环,并且实现自定义的range循环

以前我们只能这样来遍历容器或者数组

vector<int> arr {1,2,3,4,5};
for(auto it =arr.begin(); it!=arr.end(); it++
{
}

或者是

for_each(auto it=arr.begin(); it!=arr.end(); do_something);

这两种方法的弊端在于,都要写begin,和end
新的基于范围的for循环是这样的

for(auto v:arr)
{
}

冒号前面的局部变量声明只要求能够支持容器类型的隐式转换。

这个for-range循环实际上只是C++的语法糖,它是下面代码的等价替换。

for(auto __begin = arr.begin(), __end = arr.end(); __begin!=__end; ++__begin
{}

也就是说只要for-range循环冒号后边的东西是个类,这个类只要实现begin(),end()方法,并且两个方法返回一个迭代器即可。迭代器正常要实现 !=重载,++重载 和 *重载。
现在我们要实现一个类似于Python的range循环
使用起来是这样

for(int i : range(2,5,2))
{
}

这个range是个函数,它返回一个我们前面说的类

我们要实现迭代器,满足要求的类,和range函数
代码如下:

#pragma once
#include <iostream>
namespace detial_range
{
	template <typename T>
	class iterator
	{
	public:
		using value_type = T;
		using size_type = size_t;
	private:
		//Q:为什么迭代次是size_type,迭代步长和起始迭代值是value_type
		//A:因为cursor_代表要迭代的次数,其肯定是正整数,但是迭代步长和迭代值则是根据我们想要迭代什么数据类型来的。
		size_type			cursor_;	//迭代次数
		const value_type	step_;		//迭代步长
		value_type			value_;		//起始迭代值
	public:
		iterator(size_type cur_start, value_type begin_value, value_type step_value) :
			cursor_(cur_start), value_(begin_value), step_(step_value)
		{
			value_ += (step_ * cursor_);
		}

		value_type operator*() const { return value_; };

		bool operator!=(const iterator& rhs)
		{
			return (cursor_ != rhs.cursor_);
		}
		iterator& operator++(void)
		{
			value_ += step_;
			++cursor_;
			return (*this);
		}
	};

	//range类的具体实现
	template<typename T>
	class impl
	{
	public:
		using value_type = T;
		using reference = const value_type&;
		using const_reference = const value_type&;
		using iterator = const detial_range::iterator<value_type>;
		using const_iterator = const detial_range::iterator<value_type>;
		using size_type = typename iterator::size_type;

	private:
		const value_type begin_;
		const value_type end_;
		const value_type step_;
		const size_type max_conut_;//要迭代的次数

		//因为step_可能不是end_-begin_的最大公约数,所以需要调整迭代次数
		size_type get_adjust_conut(void) const
		{
			if (step_ > 0 && begin_ >= end_)
				throw std::logic_error("end_ 必须大于 begin_");
			else if (step_ < 0 && begin_ <= end_)
				throw std::logic_error("end_ 必须小于 begin_");

			size_type x = static_cast<size_type> ((end_ - begin_) / step_);
			if ((begin_ + step_ * x) != end_)++x;
			return x;
		}

	public:	//外部接口
		impl(value_type begin_value, value_type end_value, value_type step_value)
			:begin_(begin_value), end_(end_value), step_(step_value), max_conut_(get_adjust_conut())
		{}

		size_type size() const
		{
			return max_conut_;
		}

		const_iterator begin() const
		{
			return { 0,begin_, step_ };
		}

		const_iterator end() const
		{
			return const_iterator{ max_conut_, begin_, step_ };
		}
	};

	//range的外敷函数模板
	template<typename T>
	detial_range::impl<T> range(T end)
	{
		return { {},end,1 };
	}

	template<typename T>
	detial_range::impl<T> range(T begin, T end)
	{
		return { begin, end, 1 };
	}

	template <typename T, typename U>
	auto range(T begin, T end, U step) -> detial_range::impl<decltype (begin + step)>
	{
		using r_t = detial_range::impl<decltype(begin + step)>;
		return r_t{ begin ,end,step };
	}
};

void main()
{
	for (int i : detial_range::range(2, 5,2))
	{
		std::cout << "range(2,5) i:" << i << std::endl;
	}
}
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值