std::revers...::operator[](3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’… std::reverse_iterator::operator[] πŸ’…

okay so bestie, welcome to the C++ Standard Libary manual (yes that's the manual name, don't come for me), and today's main character is std::reverse_iterator::operator[] β€” same name twice in the NAME section, iconic of it honestly. It's giving "I contain multitudes" but make it a subscript operator. πŸ¦‹


✨ NAME ✨

std::reverse_iterator::operator[] β€” literally std::reverse_iterator::operator[]. That's the name. That's the whole name. Periodt. πŸ’…


πŸ” Synopsis πŸ”

until C++17 β€” no constexpr, we were all just vibing:

/* unspecified */ operator[]( difference_type n ) const;

since C++17 β€” glow-up era, constexpr entered the chat:

constexpr /* unspecified */ operator[]( difference_type n ) const;

πŸŽ€ Parameters πŸŽ€

  • n β€” position relative to the current location. that's it, that's the whole parameter, she's low maintenance 🫢

πŸ‘‘ Return value πŸ‘‘

A reference to the element at that relative location, which is to say:

base()[-n - 1]

yes the minus sign is on the n. yes it's reversed. she's a reverse iterator, what did you expect 😭πŸ”₯


🧠 Notes 🧠

okay this is the messy lore part, buckle up. The return type was changed by LWG386 to be unspecified because the return type of the underlying iterator's operator[] was also unspecified at the time. Like, nobody knew what it was. Mystery. Unknowable. πŸ™ˆ

BUT β€” as of N3066, the return type of a LegacyRandomAccessIterator's operator[] is required to be convertible to reference. In all common implementations, the return type of reverse_iterator::operator[] is declared to be reference. so like, in practice we all know what it is. ✨

See also LWG2595. iykyk. πŸ’œ


🌸 Example 🌸

// Run this code
#include <array>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>

int main()
{
    int a[]{0, 1, 2, 3};
    std::reverse_iterator<int*> iter1{std::rbegin(a)};
    for (std::size_t i{}; i != std::size(a); ++i)
        std::cout << iter1[i] << ' '; // decltype(iter1[i]) is `int&`
    std::cout << '\n';

    std::vector v{0, 1, 2, 3};
    std::reverse_iterator<std::vector<int>::iterator> iter2{std::rbegin(v)};
    for (std::size_t i{}; i != std::size(v); ++i)
        std::cout << iter2[i] << ' '; // decltype(iter2[i]) is `int&`
    std::cout << '\n';

    // constexpr context
    constexpr static std::array<int, 4> z{0, 1, 2, 3};
    constexpr std::reverse_iterator<decltype(z)::const_iterator> iter3{std::crbegin(z)};
    static_assert(iter3[1] == 2);

    std::list li{0, 1, 2, 3};
    std::reverse_iterator<std::list<int>::iterator> iter4{std::rbegin(li)};
    *iter4 = 42;   // OK
//  iter4[0] = 13; // compilation error: the underlying iterator
                   // does not model the random access iterator
}
and yes bestie, that last commented-out line is a compilation error on purpose β€” the underlying iterator doesn't model the random access iterator. std::list is a linked-list girlie, she does not do random access, do not try her. πŸ’€

🌈 Output 🌈

3 2 1 0
3 2 1 0

look at her go. reversed. flawless. ate and left no crumbs. πŸ”₯


πŸ¦‹ Defect reports πŸ¦‹

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. time travel but make it standardization πŸ’«

  • LWG 386 β€” applied to C++98 β€” behavior as published: the return type was reference β€” correct behavior: made unspecified.

⭐ See also ⭐

  • operator* β€” accesses the pointed-to element
  • operator-> (public member function)

okay that's the whole page, you're welcome, go write something reversed and slay πŸ’–βœ¨

sign-off besties: this lil artifact came from http://cppreference.com, dated 2024.06.10, and the page was std::revers...::operator[](3) β€” mwah, ily, bye πŸŽ€πŸ«Ά

πŸ“¦ where this page comes from