Implement C++20 bidirectional_iterator concept

Forward_iterator compiles fine!

#include <concepts>
#include <iterator>
// #include <iterator_concept>

using namespace std;

template<typename T>
// struct my_iterator : std::forward_iterator_tag{
struct my_iterator : std::bidirectional_iterator_tag {
   T& operator*()const{
      return *pointer;
   }
   
   my_iterator& operator++(){
      ++pointer;
      return *this;
   }
   my_iterator operator++(int){
      auto copy = *this;
      ++pointer;
      return copy;
   }
   
//    my_iterator& operator--(){
//       --pointer;
//       return *this;
//    }
//    my_iterator operator--(int){
//       auto copy = *this;
//       --pointer;
//       return copy;
//    }
   
   using difference_type = ptrdiff_t;
   using value_type = T;
   
   // auto operator<=>(const my_iterator&) const = default;
   bool operator==(const my_iterator& other)const{
      return pointer == other.pointer;
   }
   bool operator!=(const my_iterator& other)const{
      return pointer != other.pointer;
   }
   
private:
   T*pointer;
};
// template<class T> constexpr bool always_false = false;
// static_assert(always_false<std::iter_reference_t<my_iterator<int>>>, "asd");
// typedef typename std::iter_reference_t<my_iterator<int>>::something_made_up X;
// static_assert(std::weakly_incrementable<my_iterator<int>>);
// static_assert(std::equality_comparable<my_iterator<int>>);
static_assert(std::forward_iterator<my_iterator<int>>);
// static_assert(std::bidirectional_iterator<my_iterator<int>>);

int main()
{
   my_iterator<int> i1;
}

live snippet godbolt

but bidirectional does not. I tried g++ v10 and clang++ v11. Both give nearly the same compile time error.

#include <concepts>
#include <iterator>

using namespace std;

template<typename T>
// struct my_iterator : std::forward_iterator_tag{
struct my_iterator : std::bidirectional_iterator_tag {
   T& operator*()const{
      return *pointer;
   }
   
   my_iterator& operator++(){
      ++pointer;
      return *this;
   }
   my_iterator operator++(int){
      auto copy = *this;
      ++pointer;
      return copy;
   }
   
   my_iterator& operator--(){
      --pointer;
      return *this;
   }
   my_iterator operator--(int){
      auto copy = *this;
      --pointer;
      return copy;
   }
   
   using difference_type = ptrdiff_t;
   using value_type = T;
   
   // auto operator<=>(const my_iterator&) const = default;  // Why this does not work
   bool operator==(const my_iterator& other)const{
      return pointer == other.pointer;
   }
   bool operator!=(const my_iterator& other)const{
      return pointer != other.pointer;
   }
   
private:
   T*pointer;
};
// template<class T> constexpr bool always_false = false;
// static_assert(always_false<std::iter_reference_t<my_iterator<int>>>, "asd");
// typedef typename std::iter_reference_t<my_iterator<int>>::something_made_up X;
// static_assert(std::weakly_incrementable<my_iterator<int>>);
// static_assert(std::equality_comparable<my_iterator<int>>);
static_assert(std::forward_iterator<my_iterator<int>>);
// static_assert(std::bidirectional_iterator<my_iterator<int>>);

int main()
{
   my_iterator<int> i1;
}

live

In file included from <source>:2:
In file included from /opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/iterator:61:
In file included from /opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/stl_iterator_base_types.h:71:
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:409:52: error: ambiguous partial specializations of '__cat<my_iterator<int>>'
      using iterator_category = typename __detail::__cat<_Iterator>::type;
                                                   ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/stl_iterator_base_types.h:178:14: note: in instantiation of template class 'std::__iterator_traits<my_iterator<int>, void>' requested here
    : public __iterator_traits<_Iterator> { };
             ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:182:71: note: in instantiation of template class 'std::iterator_traits<my_iterator<int>>' requested here
        = __is_base_of(__iterator_traits<_Iter, void>, iterator_traits<_Iter>);
                                                                             ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:182:4: note: while substituting template arguments into constraint expression here
        = __is_base_of(__iterator_traits<_Iter, void>, iterator_traits<_Iter>);
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:189:16: note: while checking the satisfaction of concept '__primary_traits_iter<my_iterator<int>>' requested here
      requires __primary_traits_iter<_Iter>
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:189:16: note: while substituting template arguments into constraint expression here
      requires __primary_traits_iter<_Iter>
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:195:7: note: (skipping 10 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
      using __iter_traits = typename __iter_traits_impl<_Iter, _Tp>::type;
      ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:564:30: note: while checking the satisfaction of concept 'input_or_output_iterator<my_iterator<int>>' requested here
    concept input_iterator = input_or_output_iterator<_Iter>
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:564:30: note: while substituting template arguments into constraint expression here
    concept input_iterator = input_or_output_iterator<_Iter>
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:575:32: note: while checking the satisfaction of concept 'input_iterator<my_iterator<int>>' requested here
    concept forward_iterator = input_iterator<_Iter>
                               ^~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:575:32: note: while substituting template arguments into constraint expression here
    concept forward_iterator = input_iterator<_Iter>
                               ^~~~~~~~~~~~~~~~~~~~~
<source>:52:15: note: while checking the satisfaction of concept 'forward_iterator<my_iterator<int>>' requested here
static_assert(std::forward_iterator<my_iterator<int>>);
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:369:14: note: partial specialization matches [with _Iter = my_iterator<int>]
      struct __cat<_Iter>
             ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:375:14: note: partial specialization matches [with _Iter = my_iterator<int>]
      struct __cat<_Iter>
             ^
<source>:52:1: error: static_assert failed
static_assert(std::forward_iterator<my_iterator<int>>);
^                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:52:20: note: because 'my_iterator<int>' does not satisfy 'forward_iterator'
static_assert(std::forward_iterator<my_iterator<int>>);
                   ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:575:32: note: because 'my_iterator<int>' does not satisfy 'input_iterator'
    concept forward_iterator = input_iterator<_Iter>
                               ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:564:30: note: because 'my_iterator<int>' does not satisfy 'input_or_output_iterator'
    concept input_iterator = input_or_output_iterator<_Iter>
                             ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:544:5: note: because 'my_iterator<int>' does not satisfy 'weakly_incrementable'
        && weakly_incrementable<_Iter>;
           ^
/opt/compiler-explorer/gcc-10.2.0/lib/gcc/x86_64-linux-gnu/10.2.0/../../../../include/c++/10.2.0/bits/iterator_concepts.h:198:7: note: because 'typename iter_difference_t<_Iter>' would be invalid: no type named 'difference_type' in 'std::iterator_traits<my_iterator<int>>'
      using __iter_diff_t = typename
      ^
2 errors generated.
Compiler returned: 1

x86-64 clang 11.0.0
1

More questions:

  1. Why auto operator<=>(const my_iterator&) const = default; does not provide == and !=? May be it does but static_assert(std::forward_iterator<my_iterator<int>>); want operator== to be explicit.

  2. Is there a way to explicitly say this struct should meet the requirements and constraints of the concept like

    template<typename T>
    struct my_iterator implements forward_iterator {};
    

    Currently I need to check it with static_assert(std::forward_iterator<my_iterator<int>>);.



Read more here: https://stackoverflow.com/questions/64948293/implement-c20-bidirectional-iterator-concept

Content Attribution

This content was originally published by kyb at Recent Questions - Stack Overflow, and is syndicated here via their RSS feed. You can read the original post over there.

%d bloggers like this: