在C ++ 17中实现迭代器和const_iterator的正确方法是什么? [英] What is the correct way to implement iterator and const_iterator in C++17?

查看:80
本文介绍了在C ++ 17中实现迭代器和const_iterator的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

实现自定义容器时,我来到需要实现迭代器的地步。当然,我不想为const和非const迭代器编写两次代码。我发现了此问题,其中详细介绍了可能的实现方式如下:

When implementing a custom container I came to the point where I needed to implement iterators. Of course I didn't want to write the code twice for const and non-const iterator. I found this question detailing a possible implementation like this:

template<class T>
class ContainerIterator {
    using pointer = T*;
    using reference = T&;
    ...
};

template<class T>
class Container {
    using iterator_type = ContainerIterator<T>;
    using const_iterator_type = ContainerIterator<const T>;
}

但是我也发现了使用模板参数的问题

template<class T, bool IsConst>
class ContainerIterator {
    using pointer = std::conditional_t<IsConst, const T*, T*>;
    using reference = std::conditional_t<IsConst, const T&, T&>;
    ...
};

template<class T>
class Container {
    using iterator_type = ContainerIterator<T, false>;
    using const_iterator_type = ContainerIterator<T, true>;
}

第一个解决方案似乎更简单,但答案是从2010年开始。 b $ b经过研究后,似乎第一个版本并未得到广泛使用,但我看不出为什么。我觉得我缺少第一个版本的一些明显缺陷。

The first solution seems to be easier, but the answer is from 2010. After doing some research, it seems, that the first version is not widely used, but I can't see why. I feel like I'm missing some obvious flaw of the first version.

所以问题变成了: / strong>

So the questions become:


  1. 第一个版本是否存在问题?

  1. Are there any problems with the first version?

如果没有,为什么版本2似乎是c ++ 17中的首选方式?还是我为什么更喜欢一个?

If no, why version #2 seems to be the preferred way in c++17? Or why should I prefer one over the other?



另外,是的,是使用 const_cast 的解决方案,或者只是复制整个代码。但是我不喜欢这两个。


Also, yes, it would be a solution to use const_cast or simply duplicate the whole code. But I don't like those two.

推荐答案

第二个实现的重点是您没有复制的内容:容易实现特定要求。即,迭代器必须隐式转换为 const_iterator

The point of the second implementation is something you didn't copy: to make it easy to implement a specific requirement. Namely, an iterator must be implicitly convertible to a const_iterator.

这里的困难在于保持琐碎的可复制性。如果您要这样做:

The difficulty here lies in preserving trivial copyability. If you were to do this:

template<class T>
class ContainerIterator {
    using pointer = T*;
    using reference = T&;
    ...
    ContainerIterator(const ContainerIterator &) = default; //Should be trivially copyable.
    ContainerIterator(const ContainerIterator<const T> &) {...}
};

那是行不通的。 const const Typename 解析为 const Typename 。因此,如果使用 const T 实例化 ContainerIterator ,那么现在您将拥有两个具有相同签名的构造函数,其中之一这是默认设置。好吧,这意味着编译器将忽略您对副本构造函数的默认设置,从而使用非平凡的副本构造函数实现。

That doesn't work. const const Typename resolves down to const Typename. So if you instantiate ContainerIterator with a const T, then you now have two constructors that have the same signature, one of which is defaulted. Well, this means that the compiler will ignore your defaulting of the copy constructor and thus use you non-trivial copy constructor implementation.

这很糟糕。

有一些方法可以通过使用一些元编程工具来检测 T 的一致性来避免这种情况,但这是最简单的解决方法是将const-ness指定为模板参数:

There are ways to avoid this by using some metaprogramming tools to detect the const-ness of the T, but the easiest way to fix it is to specify the const-ness as a template parameter:

template<class T, bool IsConst>
class ContainerIterator {
    using pointer = std::conditional_t<IsConst, const T*, T*>;
    using reference = std::conditional_t<IsConst, const T&, T&>;
    ...

    ContainerIterator(const ContainerIterator &) = default; //Should be trivially copyable.
    template<bool was_const = IsConst, class = std::enable_if_t<IsConst || !was_const>>>
    ContainerIterator(const ContainerIterator<T, was_const> &) {...}
};

模板永远不会被视为复制构造函数,因此不会干扰琐碎的可复制性。如果不是 const 迭代器,这也使用SFINAE消除了转换构造函数。

Templates are never considered to be copy constructors, so this won't interfere with trivial copyability. This also uses SFINAE to eliminate the converting constructor in the event that it is not a const iterator.

也可以找到有关此模式的更多信息

这篇关于在C ++ 17中实现迭代器和const_iterator的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆