What to use for `Iterator :: pointer` when nothing makes sense?

For example, consider some hypothetical ones to_upper_iteratorthat are repeated in a range of characters, returning std::toupperfor operator*. These iterator aliases make sense to me:

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;
};

What does not make sense is what should / could be used for an alias pointer. I tried to leave it, but of course I had compilation errors. This seems to be due to the addition in C ++ 17. Generalized to en.cppreference.com for type std::iterator_traits:

If Iteratorno type-five members difference_type, value_type, pointer, referenceand iterator_category, it is not that the template members of any of these names ( std::iterator_traitsis SFINAE-friendly)

, : , pointer - - void void* - - specialize std::iterator_traits<to_upper_iterator>, pointer.

+4
3

++ OutputIterator void.

example: 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;
}
+4

to_upper_iterator::pointer , value_type, , , const, .. const CharT*

+2

, , 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, *a a->, .

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

void.

operator-> , , , , void, @ . , "" , pointer_proxy<T> (, STL), T, operator->, T* iterator pointer

0

Source: https://habr.com/ru/post/1677329/


All Articles