Creating Custom Iterators using C++20 Concepts

Using C++20 Concepts with Custom Iterators

How do I ensure my custom iterator satisfies C++20 iterator concepts?

Abstract art representing computer programming

To ensure your custom iterator satisfies C++20 iterator concepts, you need to use static_assert to check if your iterator meets the requirements of specific iterator concepts such as std::forward_iterator, std::bidirectional_iterator, etc.

Here’s an example of how to check if a custom iterator satisfies the std::forward_iterator concept:

#include <iostream>
#include <string>
#include <iterator>
#include <stdexcept>
#include <concepts>

class Player {
public:
  std::string Name;
};

class Party {
public:
  Party(Player A, Player B, Player C)
    : A{A}, B{B}, C{C} {}

  Player A, B, C;

  class Iterator {
  public:
    using iterator_category
      = std::forward_iterator_tag;
    using value_type = Player;
    using difference_type = std::ptrdiff_t;
    using pointer = Player*;
    using reference = Player&;

    Iterator() = default;
    Iterator(Party* ptr, size_t idx) 
      : Party(ptr), idx(idx) {}

    Player& operator*() const {
      if (idx == 0) return Party->A;
      if (idx == 1) return Party->B;
      if (idx == 2) return Party->C;
      throw std::out_of_range("Invalid index");
    }

    Player* operator->() const {
      return &**this;
    }

    Iterator& operator++() {
      ++idx;
      return *this;
    }

    Iterator operator++(int) {
      Iterator tmp = *this;
      ++(*this);
      return tmp;
    }

    bool operator==(const Iterator& other) const {
      return Party == other.Party && idx == other.idx;
    }

    bool operator!=(const Iterator& other) const {
      return !(*this == other);
    }

  private:
    size_t idx = 0;
    Party* Party = nullptr;
  };

  Iterator begin() { return Iterator(this, 0); }
  Iterator end() { return Iterator(this, 3); }

  static_assert(std::forward_iterator<Iterator>); 
};

int main() {
  Party P{Player{"Anna"},
    Player{"Bob"}, Player{"Cara"}};
  
  for (auto it = P.begin(); it != P.end(); ++it) {
    std::cout << it->Name << "\n";
  }
}
Anna
Bob
Cara

Explanation

  • static_assert: This line checks if the Iterator class satisfies the std::forward_iterator concept. If it doesn't, the program will not compile, and the compiler will provide helpful error messages indicating what requirements are not met.
  • Concepts and Requirements: By ensuring your iterator meets the std::forward_iterator concept, you guarantee that it supports all the necessary operations for a forward iterator, such as dereferencing, incrementing, and comparing.

Using concepts helps catch errors at compile time and makes your code more robust and easier to understand. It also ensures compatibility with standard library algorithms that rely on specific iterator categories.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved