Reputation: 333
Sorry for the ambiguous title, I couldn't find the right words to phrase it.
I'm trying to force a class to define some functions/operators to be correct. for example ForwardIterator
is required to have some operators otherwise I should get a compiler error. I have asked the question here and I was given a method with inheritance, it works perfectly but C++20 concepts seem to be more intuitive and give better errors.
The initial idea is:
template <typename T> concept is_ForwardIterator= requires(T x, T y)
{
x == y;
};
template <typename T>
requires is_ForwardIterator<T>
struct ForwardIterator {
};
Then whenever I want to implement a forward iterator I inherit from ForwardIterator
:
struct MyCustomIterator
: public ForwardIterator <MyCustomIterator>
{
bool operator ==(const MyCustomIterator& other) const;
};
But the compiler keeps complaining that MyCustomIterator
doesn't satisfy the requirement:
error: constraints not satisfied for class template 'ForwardIterator' [with T = MyCustomIterator]
note: because 'MyCustomIterator' does not satisfy 'is_ForwardIterator'
template <typename T> requires is_ForwardIterator<T> struct ForwardIterator {
^
note: because 'x == y' would be invalid: invalid operands to binary expression ('MyCustomIterator' and 'MyCustomIterator')
x == y;
Upvotes: 1
Views: 775
Reputation: 217235
In CRTP, derived class in incomplete, so checking its property is not possible.
One way to check interface with traits/concept is simply static_assert
after the class:
template <typename T> concept is_ForwardIterator= requires(T x, T y)
{
x == y;
// ...
};
struct MyCustomIterator
{
bool operator ==(const MyCustomIterator& other) const;
// ...
};
static_assert(is_ForwardIterator<MyCustomIterator>);
Upvotes: 1
Reputation: 157344
The problem is that where the constraint on ForwardIterator
is specified, the class T
(that is, MyCustomIterator
) is incomplete - it exists as a class name only.
You need to delay checking of the constraint until after MyCustomIterator
is complete. One way to do this is a constraint on the destructor of ForwardIterator
:
template <typename T>
struct ForwardIterator {
~ForwardIterator() requires is_ForwardIterator<T> {}
};
The only problem here is that this will not be checked until there is a reason to instantiate the destructor ~ForwardIterator
, i.e. if you do not actually instantiate a MyCustomIterator
object it will not be checked. But this should not be a problem in practice.
Upvotes: 2
Reputation: 473352
When you try to use the CRTP, during the compilation of the base class template, the derived class is incomplete. As such, asking most questions about its behavior is impossible. This includes most of the reasons to use a concept.
What you're trying to do cannot reasonably be done that way. You may need a traits class or something, depending on what your goal is.
Upvotes: 2