Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you use constraints on derived classes in CRTP methods?

Tags:

c++

c++20

crtp

Is something like this valid C++20 code?

#include <iostream>

template <typename T>
concept impls_decrement = requires(T it) { it.decrement(); };

template <class Derived>
struct iterator_facade {
  Derived& operator--()
    requires impls_decrement<Derived>
  {
    auto& self = static_cast<Derived&>(*this);
    self.decrement();
    return self;
  }
};

struct my_iterator : iterator_facade<my_iterator> {
  void decrement() {
    std::cout << "decrement" << std::endl;
  }
};

int main() {
   my_iterator iter;
   --iter;
   return 0;
}

Adapted from vector-of-bool blog post.

With the latest version of gcc, the code works fine, but the latest version of clang gives this error:

prog.cc:25:4: error: cannot decrement value of type 'my_iterator'
   --iter;
   ^ ~~~~
1 error generated.

Which compiler is correct?

like image 311
Ryan Burn Avatar asked Feb 16 '21 01:02

Ryan Burn


1 Answers

As Barry mentioned, the code is valid and this is Clang bug 44833.

In the meantime, I was able to work around the issue by writing the code like this (demo):

#include <iostream>


template <typename T>
concept impls_decrement = requires(T it) { it.decrement(); };

template <class Derived>
struct iterator_facade {
  template <class T=Derived>
    requires impls_decrement<T>
  Derived& operator--()
  {
    auto& self = static_cast<Derived&>(*this);
    self.decrement();
    return self;
  }
};

struct my_iterator : iterator_facade<my_iterator> {
  void decrement() {
    std::cout << "decrement" << std::endl;
  }
};

int main() {
   my_iterator iter;
   --iter;
   return 0;
}
like image 122
Ryan Burn Avatar answered Nov 09 '22 16:11

Ryan Burn