当没有任何意义时,用于`Iterator :: pointer`的内容是什么?

时间:2017-05-17 08:13:09

标签: c++

例如,考虑一些假设的to_upper_iterator迭代一系列字符,为std::toupper返回operator*。这些迭代器别名对我有意义:

template <typename CharT>
struct to_upper_iterator
{
    using value_type = CharT;
    using reference = CharT;
    using difference_type = std::ptrdiff_t;
    using iterator_category = std::random_access_iterator_tag;
};

没有有意义的是pointer别名应该/可以使用的内容。我试着把它关掉,但果然我有编译错误。似乎这是由于C ++中的添加17。 en.cppreference.comstd::iterator_traits类型汇总:

  

如果Iterator没有五种成员类型difference_typevalue_typepointerreferenceiterator_category,那么此模板没有任何成员的名字(std::iterator_traits是SFINAE友好的)

所以问题是:对于这样的类型,我应该将pointer定义为某些 - 我最喜欢的是voidvoid* - 或者做一些像special std::iterator_traits<to_upper_iterator>这样的事情更有意义,因此它不包含pointer的别名。

3 个答案:

答案 0 :(得分:4)

OutputIterator的标准c ++模型将全部定义为void

示例:http://en.cppreference.com/w/cpp/iterator/back_insert_iterator

对于那些在迭代器类型的上下文中没有意义的类型,我倾向于这样做。

你的这个迭代器看起来像是在建模适配器的概念。在这种情况下,我可能倾向于从这些方面开始:

#include <algorithm>
#include <string>
#include <iterator>
#include <utility>
#include <iostream>

template <typename BaseIter>
struct to_upper_iterator
{
    using value_type = typename std::iterator_traits<BaseIter>::value_type;
    using reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
    using pointer = std::add_pointer_t<std::add_const_t<value_type>>;
    using difference_type = typename std::iterator_traits<BaseIter>::difference_type;
    using iterator_category = typename std::iterator_traits<BaseIter>::iterator_category;

    to_upper_iterator(BaseIter iter = BaseIter()) : iter_(iter) {}

    value_type operator*() const { return std::toupper(*underlying()); }
    to_upper_iterator& operator++()
    {
        iter_++;
        return *this;
    }

    to_upper_iterator operator++(int)
    {
        auto copy = *this;
        iter_++;
        return copy;
    }

    bool operator!=(const to_upper_iterator& other) const {
        return iter_ != other.iter_;
    }

    // etc. use enable_if to enable functionality depending on iterator_category

private:
    BaseIter& underlying() { return iter_; }
    BaseIter const& underlying() const { return iter_; }

    BaseIter iter_;
};

template<class Iter>
auto make_upper_iterator(Iter iter)
{
    return to_upper_iterator<Iter>(iter);
}

int main()
{
    std::string a = "abcdef";

    auto first = make_upper_iterator(a.begin());
    auto last = make_upper_iterator(a.end());

    std::copy(first, last, std::ostream_iterator<char>(std::cout));
    std::cout << std::endl;

    const char b[] = "abcdef";
    std::copy(make_upper_iterator(std::begin(b)),
        make_upper_iterator(std::end(b) - 1),
        std::ostream_iterator<char>(std::cout));
    std::cout << std::endl;
}

答案 1 :(得分:2)

to_upper_iterator::pointer应该是一种可以指向value_type的类型,并标记您无法修改应该使其成为常量的值,即const CharT*

答案 2 :(得分:0)

添加我自己的答案,但假设SO不强迫我,不会将其标记为答案。似乎相关的措辞在§27.4.1

  

27.4.1迭代器特征[iterator.traits]

     

要仅根据迭代器实现算法,通常需要确定值和差异   与特定迭代器类型对应的类型。因此,如果Iterator是类型,则需要   迭代器,类型

iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::iterator_category
     

分别定义为迭代器的差异类型,值类型和迭代器类别。除此之外   类型

iterator_traits<Iterator>::reference
iterator_traits<Iterator>::pointer
     

应定义为迭代器的引用和指针类型,即对于迭代器对象a,类型相同   分别为*aa->的类型。在输出迭代器的情况下,类型

iterator_traits<Iterator>::difference_type
iterator_traits<Iterator>::value_type
iterator_traits<Iterator>::reference
iterator_traits<Iterator>::pointer
     

可以定义为void

在我的情况下,operator->没有意义,因为我只是返回字符类型,所以我可能会因为@Richard Hodges的建议而逃脱void。我认为一般情况下的“正确”答案是定义一些pointer_proxy<T>类型(假设STL中尚不存在这样的东西),其中包含T并定义operator->返回T*并将其用于迭代器的pointer类型