首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >迭代器的Const包装器

迭代器的Const包装器
EN

Code Review用户
提问于 2020-10-11 09:26:25
回答 1查看 269关注 0票数 3

编辑__:增加了为什么要这样做的说明,并更新了代码,因为我还没有任何答案

我有一个类似C++11数组的类,它可以是一个随机访问迭代器的包装器。基于索引的访问和.begin()/.end()可以直接传递给迭代器,但是当对象是const时会有一些复杂:

代码语言:javascript
复制
    template
    class Storage : public Size {
        DataIterator iterator;
    public:
        Storage(const DataIterator &iterator, const Size &size) : Size(size), iterator(iterator) {}
        
        auto operator[](index_t i)
                -> decltype(iterator[i]) {
            return iterator[i];
        }
        auto operator[](index_t i) const
                -> MakeConst {
            return iterator[i];
        }
        
        DataIterator begin() {return iterator;}
        ConstWrapper begin() const {return iterator;}
        DataIterator end() {return iterator + this->size();}
        ConstWrapper end() const {return iterator + this->size();}
    };

如果我们简单地从const版本的.begin().end()返回D6,那么持有Storage const &的人就会(错误地!)能够通过该迭代器修改数组。

std::vector这样的容器有两个独立的迭代器(::iterator::const_iterator),但是我们的Storage类只有读写类,所以我们使用ConstWrapper来合成一个:

代码语言:javascript
复制
    template 
    class ConstWrapper {
        Iterator iterator;

        using traits = std::iterator_traits;
    public:
        using difference_type = typename traits::difference_type;
        using value_type = typename traits::value_type;
        using pointer = ConstWrapper;
        using reference = MakeConst;
        using iterator_category = typename traits::iterator_category;
    
        ConstWrapper() {}
        ConstWrapper(const Iterator &iterator) : iterator(iterator) {}
        
        // The problematic cases:
        auto operator[](index_t i) const
                -> MakeConst {
            return iterator[i];
        }
        auto operator*() const
                -> MakeConst {
            return *iterator;
        }

        bool operator!= (const ConstWrapper& other) const {
            return iterator != other.iterator;
        }
        /** All the other random-access iterator methods **/
    };
    
    // Specialisation to prevent infinite loops
    template 
    class ConstWrapper> : ConstWrapper {
    public:
        using ConstWrapper::ConstWrapper;
    };

该实现转发了所有相关方法,并对ConstWrapper>进行了专门化,使其不能自行包装。

关键部分是MakeConst,它将类型转换为正确的const变量(与简单添加const不同,后者对引用没有影响):

代码语言:javascript
复制
    // Converts (T & -> T const &), and (T -> const T)
    using MakeConst = typename std::conditional<
        std::is_reference::value,
        typename std::remove_reference::type const &,
        const T
    >::type;

这有道理吗,还好吗?我还能做些更易读/更有效率的事情吗?

谢谢!

EN

回答 1

Code Review用户

发布于 2020-10-25 06:30:50

我不认为你的专长是做你认为它正在做的事。https://godbolt.org/z/Gfh7sv

您不希望ConstWrapper>ConstWrapper继承;这意味着CW>“是一种”CW,这不是真的。你不想在这里建立继承关系。您想要的只是Storage的专门化,而不是包装DataIterators (碰巧已经是ConstWrapper的专门化)。您这样做的方式是使用额外的一层间接别名:

代码语言:javascript
复制
template struct maybe_constwrap { using type = ConstWrapper; };
template struct maybe_constwrap> { using type = ConstWrapper; };

template
class Storage : public Size {
public:
    using iterator = DataIterator;
    using const_iterator = typename maybe_constwrap::type;
    ~~~
};

现在,如果DataIterator已经是一个ConstWrapper,那么iteratorconst_iterator实际上都是相同的类型.这就是你想要的。

您的MakeConst似乎是建立在一个可疑的想法之上的,即const _Bit_reference是不可分配的。这可能会在C++23中发生变化。有关某些上下文,请参见https://stackoverflow.com/questions/63412623/should-c20-stdrangessort-not-need-to-support-stdvectorbool

operator*operator[]的返回类型中重复一些元编程。它们应该只返回前面已经计算过的reference类型。

代码语言:javascript
复制
reference operator*() const { return *it_; }

顺便说一句,我正在将您的数据成员的名称从iterator更改为it_,因为我怀疑有一个名为iterator的成员的容器级类型是一个糟糕的想法,它的成员名为(A)不公开,(B)不是一个类型。

您的operator!=可能应该使用隐藏的朋友成语:

代码语言:javascript
复制
friend bool operator==(ConstWrapper a, ConstWrapper b) { return a.it_ == b.it_; }
friend bool operator!=(ConstWrapper a, ConstWrapper b) { return a.it_ != b.it_; }

在C++20中,理论上您可以省略operator!=,只提供operator==。我还不知道这是不是个好主意。

通过值传递ConstWrapper应该很好,因为它只包含一个迭代器,而且迭代器的复制成本很低。

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

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

复制
相关文章

相似问题

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