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

struct Data
{
    using value_type        = std::string;

    struct iterator
    {
        using iterator_category = std::forward_iterator_tag;
        using difference_type   = std::ptrdiff_t;
        using value_type        = std::string;
        using pointer           = value_type const *;
        using reference         = value_type const &;

        friend class Data;

        friend bool operator==(iterator const &lhs, iterator const &rhs);
// or (see below):
//        friend auto operator<=>(iterator const &lhs, iterator const &rhs);

        private:
            std::vector<std::string>::const_iterator d_iter;

        public:
            std::string const &operator*() const;
            iterator &operator++();
            iterator &operator--();

        private:
            iterator(std::vector<std::string>::const_iterator iter);
    };

    private:
        static std::vector<std::string> s_data;
        std::vector<std::string> d_data;

    public:
        void push_back(std::string const &txt);

        iterator begin() const;
        iterator end() const;

        std::reverse_iterator<iterator> rbegin() const;
        auto rend() const;
};

inline void Data::push_back(std::string const &txt)
{
    std::cout << "pushing back: " << txt << '\n';
}

inline std::string const &Data::iterator::operator*() const
{
    return *d_iter;
}

Data::iterator &Data::iterator::operator++()
{
    ++d_iter;
    return *this;
}

Data::iterator &Data::iterator::operator--()
{
    --d_iter;
    return *this;
}

inline Data::iterator::iterator(std::vector<std::string>::const_iterator iter)
:
    d_iter(iter)
{}


std::reverse_iterator<Data::iterator> Data::rbegin() const
{
    return std::reverse_iterator(end());
}

auto Data::rend() const
{
    return std::reverse_iterator(begin());
}

inline Data::iterator Data::begin() const
{
    return s_data.cbegin();
}

inline Data::iterator Data::end() const
{
    return s_data.cend();
}

inline bool operator==(Data::iterator const &lhs, Data::iterator const &rhs)
{
    return lhs.d_iter == rhs.d_iter;
}

inline bool operator!=(Data::iterator const &lhs, Data::iterator const &rhs)
{
    return not (lhs == rhs);
}
// or:
//inline auto operator<=>(Data::iterator const &lhs, Data::iterator const &rhs)
//{
//    return lhs.d_iter <=> rhs.d_iter;
//}


std::vector<std::string> Data::s_data{
                                "alpha", "bravo", "charley", "delta", "echo"
                            };

using namespace std;

int main()
{
    Data data;

    for( string const &str: data)
        cout << str << ' ';
    cout << '\n';

    copy(data.begin(), data.end(), ostream_iterator<string>(cout, ", "));
    cout << '\n';

    copy(data.rbegin(), data.rend(), ostream_iterator<string>(cout, ", "));
    cout << '\n';

    copy(data.begin(), data.end(), back_inserter(data));
}
