首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于间接迭代的C++自定义迭代器

用于间接迭代的C++自定义迭代器
EN

Code Review用户
提问于 2018-01-17 20:20:14
回答 1查看 851关注 0票数 4

这个程序不完全符合前相关问题,但基本上是一样的:给定一个元素集合和一个索引集合,根据索引序列通过迭代器集合元素返回。下面是:

代码语言:javascript
复制
#include <exception>
#include <iostream>
#include <iterator>
#include <list>
#include <sstream>
#include <vector>

template<typename ForwardIterator, typename IndexIterator>
class indirection_iterator {
public:
    indirection_iterator(ForwardIterator element_begin,
                         ForwardIterator element_end,
                         IndexIterator index_begin,
                         IndexIterator index_end)
    :
    m_element_begin{element_begin},
    m_element_end{element_end},
    m_index_begin{index_begin},
    m_index_end{index_end},
    m_index_current{index_begin},
    m_elements{std::distance(element_begin, element_end)}
    {}

    indirection_iterator begin()
    {
        return indirection_iterator{m_element_begin,
                                    m_element_end,
                                    m_index_begin,
                                    m_index_end,
                                    m_index_begin};
    }

    indirection_iterator end()
    {
        return indirection_iterator{m_element_begin,
                                    m_element_end,
                                    m_index_begin,
                                    m_index_end,
                                    m_index_end};
    }

    auto operator*()
    {
        auto index = *m_index_current;
        check_index(index, m_elements);
        auto element_iterator = m_element_begin;
        std::advance(element_iterator, index);
        return *element_iterator;
    }

    void operator++()
    {
        std::advance(m_index_current, 1);
    }

    bool operator!=(indirection_iterator const& other)
    {
        return m_index_current != other.m_index_current;
    }

private:

    indirection_iterator(ForwardIterator element_begin,
                         ForwardIterator element_end,
                         IndexIterator index_begin,
                         IndexIterator index_end,
                         IndexIterator index_current)
    :
    m_element_begin{element_begin},
    m_element_end{element_end},
    m_index_begin{index_begin},
    m_index_end{index_end},
    m_index_current{index_current},
    m_elements{std::distance(element_begin, element_end)}
    {}

    template<typename IndexIter>
    using index_type = typename std::iterator_traits<IndexIter>::value_type;

    ForwardIterator m_element_begin;
    ForwardIterator m_element_end;
    IndexIterator m_index_begin;
    IndexIterator m_index_end;
    IndexIterator m_index_current;
    typename std::iterator_traits<ForwardIterator>::difference_type m_elements;

    template<typename index_type>
    void check_index(index_type index, size_t elements)
    {
        if (index < 0)
        {
            std::stringstream ss;
            ss << "index(" << index << ") < 0";
            throw std::runtime_error{ss.str()};
        }

        if (index >= elements)
        {
            std::stringstream ss;
            ss << "index(" << index << ") >= elements(" << elements << ")";
            throw std::runtime_error{ss.str()};
        }
    }
};


static std::vector<char> get_alphabet() {
    std::vector<char> alphabet;

    for (char ch = 'a'; ch <= 'z'; ch++)
    {
        alphabet.push_back(ch);
    }

    for (char ch = 'A'; ch <= 'Z'; ch++)
    {
        alphabet.push_back(ch);
    }

    alphabet.push_back(',');
    alphabet.push_back(' ');
    alphabet.push_back('!');
    alphabet.push_back('\n');

    return alphabet;
}

int main(int argc, const char * argv[]) {
    std::vector<char> alphabet = get_alphabet();
    std::list<int> char_indices =
    { 33, 4, 11, 11, 14, 52, 53, 48, 14, 17, 11, 3, 54, 55 };

    indirection_iterator<decltype(alphabet.cbegin()),
                         decltype(char_indices.cbegin())> indirection_iter {
        alphabet.cbegin(),
        alphabet.cend(),
        char_indices.cbegin(),
        char_indices.cend()
    };

    std::copy(indirection_iter.begin(),
              indirection_iter.end(),
              std::ostream_iterator<char>{std::cout});
    return 0;
}

评论请求

我想听听如何使它更有用,以及如何使它更地道的C++。

EN

回答 1

Code Review用户

发布于 2018-01-18 12:40:26

-可移植性问题

我知道这只是测试代码,而不是审查的真正主题,但值得一提的是。

代码语言:javascript
复制
for (char ch = 'a'; ch <= 'z'; ch++)
{
    alphabet.push_back(ch);
}

这并不一定要做您认为它做的事情;它取决于目标的字符编码。在EBCDIC语言环境中,这将插入41个值,这将抛出您的索引。

从字符串文本初始化更安全、更清晰:

代码语言:javascript
复制
static std::vector<char> get_alphabet() {
    static char const s[] = ""
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        ", !\n";

    return {std::begin(s), std::end(s)};
}

迭代器接口

GCC警告( -Weffc++),operator++()应该按惯例返回对*this的引用,而不是void。许多方法也可以/应该声明为const (至少根据我的测试,beginendoperator*operator!=check_index )。

用户不可计算建议我将操作者超载 (关于cppreference.com)作为常用函数签名的有用列表。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/185343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档