Creatig自定义end()迭代器

时间:2018-10-15 09:13:43

标签: c++ iterator

我必须创建Iterator类,在向量中迭代序列以完成任务,但是在task中使用了基于范围的for循环,例如:

for (T element: sequence) {
    std::cout << element << " ";
    std::cin >> numToGenerate;
    sequence.generateNext(numToGenerate);
}

因此,我应该创建自己的Sequence和Iterator类,它们可以完成任务,但我不知道如何执行end()迭代器。

这是到目前为止的代码:

template<typename T, typename Generator>
class Sequence
{
std::vector<T> elements;
Generator generator;

public:
class Iterator
{
public:
    int index;
    std::vector<T>& elements;

    Iterator(int index, std::vector<T>& elements) : index(index), elements(elements) {};

    void operator++()
    {
        this->index++;
    }

    T operator*()
    {
        return this->elements[this->index];
    }

    bool operator!= ( Iterator other)
    {
        return this->index != other.index;
    }
};

void generateNext(int numToGenerate)
{
    for (int i = 0; i < numToGenerate; i++)
    {
        T next = generator();
        elements.push_back(next);
    }
}

Iterator begin()  
{
    return Iterator(0, elements);
}

Iterator end() 
{
    //??????????
}
};    

4 个答案:

答案 0 :(得分:1)

您可以创建结束迭代器,该迭代器指向向量中最后一个元素之外的某个位置,就像'std :: vector的迭代器一样。

Iterator end()  
{
    return Iterator(elements.size(), elements);
}

作为替代方案,您可以只使用std::vector::iterator,并为其创建包装器beginend方法。

答案 1 :(得分:0)

我不得不说,我觉得你的动机值得怀疑。为什么要 遍历元素时将元素推到末尾?

您的generateNext不依赖于索引。无论您使用什么索引,都必须一直推到最后(这意味着Generator必须记住它已经产生了什么元素,即保留一个索引,这不是序列应该做的吗?)。

假设您的循环是书面形式,则只有在用户多次键入0直到序列结束时,循环才能结束。将元素插入序列的自然方法是您在generateNext中实现的方法。我不知道为什么要干预序列以进行迭代。

无论如何,如果对end迭代器进行特殊比较(为了简洁起见,我省略了Generator),循环就可以正常工作了:

#include <iostream>
#include <vector>

template<typename T>
struct Sequence {
    std::vector<T> elements;
    struct Iterator {
        int index;
        std::vector<T>& elements;
        bool isEnd;
        Iterator(int index, std::vector<T>& elements,bool isEnd=false)
            : index(index), elements(elements) {};
        void operator++() { this->index++; }
        T operator*() { return this->elements[this->index]; }
        bool operator!= (const Iterator& other) {
            if (other.isEnd) return index != elements.size();
            return this->index != other.index;
        }
    };
    void generateNext(int numToGenerate) {
        static int counter = 0;
        for (int i = 0; i < numToGenerate; i++) { elements.push_back(counter+i); }
        counter += numToGenerate + 100;
    }
    Iterator begin() { return Iterator(0, elements); }
    Iterator end() { return Iterator(0,elements,true); }
};

现在您可以使用基于范围的for循环了:

int main() {
    Sequence<int> s;
    s.generateNext(5);
    for (auto element : s) {
        if (element <3) s.generateNext(3);
    }
    for (auto element : s) { std::cout << element << " ";}
}

输出:

0 1 2 3 4 105 106 107 208 209 210 311 312 313 

请注意,我特别选择了“生成器”,以便您可以看到循环中何处生成数字。这真的是您想要的吗?让我再问一遍:为什么您会以这种方式生成序列?考虑如何填充向量:

first iteration:  0 1 2 3 4 105 106 107
                  ^--------------------this one would be printed in your loop
second iteration: 0 1 2 3 4 105 106 107 208 209 210
                    ^
third iteration:  0 1 2 3 4 105 106 107 208 209 210 311 312 313 
                      ^
and then some more iterations where we dont add elements to eventually reach the end

底线:我强烈建议您重新考虑您的设计。 for循环通常表示您事先知道必须执行多少次迭代。使用迭代器通常有助于独立于容器类型,但实际上在循环内部您确实使用了容器而不是迭代器。 end迭代器通常是“脆弱的”,因为如果您推送某些内容,那么即使没有重新分配,end之前的内容现在也不再可用。

TL; DR:改为使用while循环,类似以下内容:

sequence s;
generator g;
while (g.has_more()) s.push_back(g());

答案 2 :(得分:0)

include <iostream>

#include "Sequence.h"

class IntegersGenerator {
int last;
public:
IntegersGenerator() : last(0) {}

int operator()() {
    return this->last++;
}
};

class FibonacciGenerator{
int last;
int current;
public:
FibonacciGenerator() : last(0), current(0) {}

int operator()() {
    if (this->current == 0 && this->last == 0) {
        this->last = 1;
        return 0;
    }

    int next = this->last + this->current;
    this->last = this->current;
    this->current = next;

    return next;
}
};

template<typename T, typename Generator>
void readGenerateWrite() {
Sequence<T, Generator> sequence;

int numToGenerate;
std::cin >> numToGenerate;
sequence.generateNext(numToGenerate);

for (T element : sequence) {
    std::cout << element << " ";
    std::cin >> numToGenerate;
    sequence.generateNext(numToGenerate);
}
}

int main() {
char generatorType;
std::cin >> generatorType;
if (generatorType == 'i') {
    readGenerateWrite<int, IntegersGenerator>();
}
else if (generatorType == 'f') {
    readGenerateWrite<int, FibonacciGenerator>();
}

return 0;
}

这是任务提供给我的代码,我无法更改。 和示例: 输入:

3 1 1 0 2 0 0 0 输出:0 1 2 3 4 5 6

答案 3 :(得分:0)

本周我的任务完全相同,您的代码对我有很大帮助。您可能已经解决了任务,但是我发现end()返回什么无关紧要-它可以与begin()相同或可以成功编译的任何东西。任务的关键是运算符!=的重载,因此它将在每个周期获取新的向量大小。我通过比较变量索引和大小来做到这一点。

 bool operator!= ( Iterator other)
{

    return this->index != elements.size();
}