您的位置:首页 > 编程语言 > C语言/C++

深入应用c++11读书笔记--使用c++11让程序更简洁、更现代-2.自己实现一个支持范围for循环的类~

2016-11-16 20:41 1031 查看

开头

之前写了部分关于c++11让程序更简洁相关内容,至于分出来第二部分,是由于之前都展示的一些纯语法相关并未主动编写代码,这里有一个需要编写一些代码的,所以单独摘出来。

让基于范围的for循环(支持自定义类型)

如何让基于范围的for循环运转

具体来说,基于范围的for循环只是普通for循环的语法糖,它需要查找容器的begin和end迭代器。

1. 对于普通array对象,begin将为array首地址,end为首地址加容器长度;

2. 容器是类对象,range-based for将试图通过查找类的begin()和end()定位;

3. 其他,通过全局begin和end定位。

实现对区间的迭代

namespace detail_range {
template<typename T>
class iterator
{
public:
using value_type = T;
using size_type = size_t;
private:
size_type cursor_;
const value_type step_;
value_type value_;
public:
iterator(size_type cur_start, value_type begin_val, value_type step_val)
: cursor_(cur_start), step_(step_val), value_(begin_val)
{
value_ += (step_ * cursor_);
}

value_type operator*() const { return value_; }

bool operator!=(const iterator& rhs) const
{
return cursor_ != rhs.cursor_;
}

iterator& operator++()
{
value_ += step_;
++cursor_;
return *this;
}
};

template<typename T>
class impl
{
public:
using value_type    = T;
using reference     = value_type&;
using const_reference = const value_type&;
using iterator = detail_range::iterator<value_type>;
using const_iterator = const detail_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_count_;

size_type get_adjusted_count() const
{
if (step_ > 0 && begin_ >= end_) {
throw std::logic_error("when step > 0, end value must be greater than begin value");
} else if (step_ < 0 && begin_ <= end_) {
throw std::logic_error("when step < 0, end value must be smaller than begin value");
}
size_type count = static_cast<size_type>((end_ - begin_) / step_);
if (begin_ + (step_ * count) != end_) {
++count;
}
return count;
}
public:
impl(value_type begin_val, value_type end_val, value_type step_val)
: begin_(begin_val)
, end_(end_val)
, step_(step_val)
, max_count_(get_adjusted_count())
{}

size_type size() const
{
return max_count_;
}

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

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

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

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

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


使用:

int main()
{
for (auto i : detail_range::range(5, 20, 0.5)) {
cout << i << endl;
}
}


以上代码主要摘抄书中的例子,有几点觉得书中写得很好:

实现impl中将类型进行了统一,避免了impl中的一些不必要的复杂度,然后在rang中将step和begin类型进行统一;

using r_t = impl

尝试自己改造一个rang,支持从标准容器中间隔取值

附上代码吧,还缺少一些出错判断但能满足一般需求,待真实使用中进一步改进:

#pragma once
#include <assert.h>
namespace container_range {
template<typename T>
class iterator
{
public:
using iterator_type = T;
using size_type = size_t;
using value_type = typename iterator_type::value_type;
private:
iterator_type cursor_;
iterator_type end_;
const int step_;
public:
iterator(iterator_type cur_start, iterator_type cur_end, int step_val)
: cursor_(cur_start), end_(cur_end), step_(step_val)
{
assert(step_ >= 0);
}

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

bool operator!=(const iterator& rhs) const
{
return cursor_ != rhs.cursor_;
}

iterator& operator++()
{
auto diff = std::distance(cursor_, end_);
assert(diff >= 0);

if (step_ < diff) {
std::advance(cursor_, step_);
}
else {
cursor_ = end_;
}
return *this;
}
};

template<typename ContainerT>
class impl{
public:
using container_type = ContainerT;
using value_type = typename ContainerT::value_type;
using const_reference = typename ContainerT::const_reference;
using container_iterator_type = decltype(ContainerT().begin());
private:
ContainerT container_;
int step_;
int begin_;
public:
impl(ContainerT container, int begin, int step) : container_(container), begin_(begin), step_(step) {}

iterator<container_iterator_type> begin() {
auto beginIt = container_.begin();
std::advance(beginIt, begin_);
return{ beginIt, container_.end(), step_};
}

iterator<container_iterator_type> end() {
return{ container_.end(), container_.end(), step_};
}
};

template<typename ContainerT>
impl<ContainerT> range(ContainerT container, int begin, int step) {
return{container, begin, step};
}
}


下面是使用例子:

#include <iostream>
#include "containerRange.h"
#include <list>

int main()
{
std::list<int>  l = {1, 2, 3, 4, 5, 6, 7};
for (auto i : container_range::range(l, 0, 2)) { //  从第一个1个元素开始取,间隔为2
std::cout << i << std::endl;
}
int v = 0;
std::cin >> v;
return 0;
}


输出结果如下,满足初始设计要求。

1

3

5

7
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐