简体   繁体   English

c ++ foreach循环使用指针而不是引用

[英]c++ foreach loop with pointers instead of references

I have this Container class with begin() and end() functions for use with c++11 foreach loops: 我有这个带有begin()和end()函数的Container类,用于c ++ 11 foreach循环:

class Element
{
    //content doesn't matter
};

class Container
{
    Element* elements;
    int size;

    /* constructor, destructor, operators, methods, etc.. */

    Element* begin() { return elements; };
    Element* end()   { return elements + size; };
};

This is now a valid c++11 foreach loop: 这是一个有效的c ++ 11 foreach循环:

Container container;
for (Element& e : container)
{
    //do something
}

But now consider this foreach loop: 但现在考虑这个foreach循环:

Container container;
for (Element* e : container)
{
    //do something
}

Is it possible to have a foreach loop with Element* instead of Element& like this? 是否可以使用Element*而不是Element&这样的foreach循环?
This would also have the great advantage of preventing one from typing for (Element e : container) which would copy the element each time. 这也有很大的优势,可以阻止人们输入for (Element e : container) ,每次都会复制元素。

In that case begin() and end() would have to return Element** as far as I know. 在这种情况下,就我所知, begin()end()必须返回Element**

But sizeof(Element) is not guaranteed to be sizeof(Element*) and in most cases they don't match. sizeof(Element)不保证是sizeof(Element*) ,在大多数情况下它们不匹配。 Incrementing a pointer increments by the base type size which is sizeof(Element) for incrementing Element* and sizeof(Element*) for incrementing Element** . 增加指针增量的基本类型大小是sizeof(Element)用于递增Element*sizeof(Element*)以递增Element**

So the prefix operator++() will offset the pointer by a false value and things get crappy. 所以前缀operator++()会将指针偏移一个假值,事情变得糟糕。 Any ideas how to get this to work? 任何想法如何让这个工作?

I agree with LRiO that what you have right now is probably the best solution. 我同意LRiO的看法 ,你现在拥有的可能是最好的解决方案。 It additionally lines up with how the standard containers operate, and taking the path of least surprise for your users is always the best path to take (barring compelling reasons to diverge). 它还与标准容器的运行方式相关联,并且为用户提供最少惊喜的路径始终是最佳途径(除非有令人信服的理由分歧)。

That said, you can certainly get the behavior you want: 也就是说,你当然可以得到你想要的行为:

class Container
{
    // ...

    struct iterator {
        Element* e;

        // this is the important one
        Element* operator*() { return e; }

        // the rest are just boilerplate
        iterator& operator++() { ++e; return *this; }
        iterator operator++(int) {
            iterator tmp{e};
            ++*this;
            return tmp;
        }

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

    iterator begin() { return {elements}; };
    iterator end()   { return {elements + size}; };
};

You could consider inheriting from std::iterator to get the typedefs right, or using boost::iterator_facade . 您可以考虑从std::iterator继承以获取rightdef,或者使用boost::iterator_facade But this'll at least give you the functionality. 但这至少可以为您提供功能。

I can see why you'd want to do this, since an Element*Element typo would be caught as an error right away, whereas an Element&Element typo is usually a silent bug. 我可以看到你为什么要这样做,因为Element*Element拼写错误会立即被捕获,而Element&Element拼写错误通常是一个无声的错误。 However, in the grand scheme of things, I don't think it's worth transforming your entire container. 然而,在宏伟的计划中,我认为不值得改造整个容器。

You could try to create a container adaptor that maintains the current behaviour of its iterators, except in the value type they expose… but I'm not even sure it's possible to do that without breaking various preconditions. 您可以尝试创建一个容器适配器来维护其迭代器的当前行为,除了它们公开的值类型...但我甚至不确定它是否可以在不破坏各种前提条件的情况下执行此操作。

Personally, I just wouldn't. 就个人而言,我不会。

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

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