简体   繁体   English

C 链表的 C++ 迭代器:使用基于范围的 for 循环

[英]C++ Iterator for C Linked Lists: to use range-based for loops

I am working with legacy C code and the new code is written in C++ .我正在使用旧的C代码,新代码是用C++编写的。 To use the C++ standard library, I wrote a simple Iterator for the legacy LinkedList as shown below after reading through Bjarne Stroustrup's blog post on Adaptation .为了使用 C++ 标准库,我在阅读了 Bjarne Stroustrup 关于Adaptation的博文后,为旧版LinkedList编写了一个简单的Iterator ,如下所示。

My question is:我的问题是:

  1. I want to create another Iterator for another struct say struct TokenList .我想为另一个struct创建另一个Iterator ,比如struct TokenList I am not sure how to use namespace and still be able to use the range-based for loops.我不确定如何使用namespace并且仍然能够使用基于范围的for循环。 Any pointers would be helpful.任何指针都会有所帮助。

  2. Are the adapters for the Iterator namely: begin , end , ++ , * , != correct? Iterator的适配器,即: beginend++*!=正确吗? Currently, I'm an interested in reading the contents of the LinkedList using range-based for loops.目前,我对使用基于范围的for循环读取LinkedList的内容很感兴趣。

Coliru科利鲁

#include <cstdio>
#include <numeric>
#include <algorithm>

struct LinkedList {
    double v;
    LinkedList *next;
};

struct Iterator {
    LinkedList *current;
    LinkedList &c;
};

Iterator begin(LinkedList *c) { return Iterator {c, *c}; }
Iterator end(LinkedList *c) { return Iterator {nullptr, *c}; }
Iterator &operator++(Iterator &p) { p.current = p.current->next; return p; }
LinkedList *operator*(Iterator p) { return p.current; }
bool operator!=(Iterator lhs, Iterator rhs) { return (lhs.current != rhs.current); }

int main()
{
    LinkedList *node1 = new LinkedList;
    LinkedList *node2 = new LinkedList;
    LinkedList *node3 = new LinkedList;

    node1->v = 1; node1->next = node2;
    node2->v = 2; node2->next = node3;
    node3->v = 3; node3->next = nullptr;

    printf("// C style: iteration\n");
    for (auto ptr = node1; ptr; ptr = ptr->next) {
        printf("%e\n", ptr->v);
    }

    auto head = node1;
    // make use of begin(), end(), ++, != and *
    printf("// Modern C++ style: range based for-loop\n");
    for (const auto& it : head) {
        printf("%e\n", it->v);
    }

    std::for_each(begin(head), end(head), [](auto t) { delete t; });

    return 0;
}

Iterators are pseudo-pointer types.迭代器是伪指针类型。 That means they themselves are regular.这意味着他们自己是有规律的。

struct Iterator {
  LinkedList *current;
  LinkedList &c;
};

Here you mix references and pointers.在这里你混合引用和指针。 This is a serious anti-pattern, as what does assignment do?这是一个严重的反模式,赋值是做什么的? There is no sensible answer.没有明智的答案。

I woukd remove the c member entirely.我会完全删除c成员。

Next you need to broadcast an iterator type.接下来你需要广播一个迭代器类型。 Yours looks like a forward iterator.你的看起来像一个前向迭代器。 All end iterators can be equal.所有结束迭代器都可以相等。

Iterator begin(LinkedList *c) { return Iterator {c, *c}; }
Iterator end(LinkedList *c) { return Iterator {nullptr, *c}; }

These look ok.这些看起来不错。

Note that the name does not have to be Iterator .请注意,名称不必是Iterator begin / end must be defined in the namespace of LinkedList , but the return type does not have to be. begin / end必须在LinkedList的命名空间中定义,但返回类型不必是。

Iterator &operator++(Iterator &p) { p.current = p.current->next; return p; }

I usually implement this as a member function, and implement both pre and post increment;我通常将其实现为成员 function,并实现前后递增; post is implemented using pre and copy. post 是使用 pre 和 copy 实现的。

LinkedList *operator*(Iterator p) { return p.current; }

This is wrong.这是错误的。 It should return *p.current as a double& .它应该返回*p.current作为double&

bool operator!=(Iterator lhs, Iterator rhs) { return (lhs.current != rhs.current); }

sure.当然。 Also implement == as !(lhs!=rhs) .还将==实现为!(lhs!=rhs)

Look up the forward iterator concept and forward iterator tag.查找前向迭代器概念和前向迭代器标签。 Include the types needed for std::iterator_traits .包括std::iterator_traits所需的类型。

For other things to iterate, give the iterator a different name.对于其他要迭代的东西,给迭代器一个不同的名字。 This can be via a different namespace.这可以通过不同的命名空间。

If the thing that differs is just the type of the value, you can make it a template pretty easy.如果不同的只是值的类型,你可以很容易地把它变成一个模板。 Then you only have to manually write begin / end .然后你只需要手动编写begin / end

If the name of v also changes, you could use ADL on a GetValue(List*) function you write as a customization point.如果v的名称也发生变化,您可以在作为自定义点编写的GetValue(List*) function 上使用 ADL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM