C++20: Define the Concepts Equal and Ordering

C++20: Define the Concepts Equal and Ordering

This is a cross-post from www.ModernesCpp.com.

In my last post, I defined the concept Equal. Now, I go one step further and use the concept Equal to define the concept Ordering.



Here is a short reminder of where I ended with my last post. I defined the concept of Equal and a function areEqual to use it.

template<typename T>
concept Equal =
    requires(T a, T b) {
        { a == b } -> bool;
        { a != b } -> bool;
};


bool areEqual(Equal auto fir, Equal auto sec) {                       
  return fir == sec;
}

My Wrong Usage of the Concept Equal

I used the concept of Equal in my last post in the wrong way. The concept Equal requires that a and b have the same type but, the function areEqual allows that fir and sec could be different types that both support the concept Equal. Using a constrained template parameter instead of placeholder syntax solves the issue: 

template <Equal T>
bool fir, T sec) {    
    fir == sec;
}

Now, fir and sec must have the same type. 

Thanks a lot to Corentin Jabot for pointing this inconsistency out. 

Additionally, the concept Equal should not check if the equal and unequal operator returns a bool but something which is implicitly or explicitly convertible to a bool. Here we are. 

template<typename T>
concept Equal =
    requires(T a, T b) {
        { a == b } -> std::convertible_to<bool>;
        { a != b } -> std::convertible_to<bool>;
};

 I have to add. std::convertible_to is a concept and requires, therefore, the header <concepts>.  

template <class From, class To>
concept convertible_to =
  std::is_convertible_v<From, To> &&
  requires(From (&f)()) {
    static_cast<To>(f());
  };

The C++ 20 standard has already defined two concepts for equality comparing:

  • std::equality_comparable: corresponds to my concept Equal
  • std::equality_comparable_with: allows the comparison of values of different type; e.g.: 1.0 == 1.0f

The Challenge

I ended my last post by presenting a part of the type class hierarchy of Haskell.

No alt text provided for this image

The class hierarchy shows that the type class Ord is a refinement of the type class Eq. This can elegantly be expressed in Haskell.

class Eq a where
    (==) :: a -> a -> Bool
    (/=) :: a -> a -> Bool

class Eq a => Ord a where
    compare :: a -> a -> Ordering
    (<) :: a -> a -> Bool
    (<=) :: a -> a -> Bool
    (>) :: a -> a -> Bool
    (>=) :: a -> a -> Bool
    max :: a -> a -> a

Here is my challenge. Can I express such as relationship quite elegantly with concepts in C++20? For simplicity reasons, I ignore the functions compare and max of Haskell's type class. Of course, I can.

The Concept Ordering

Thanks to requires-expression, the definition of the concept Ordering looks quite similar to the definition of the type class Equal.  

template <typename T>
concept Ordering =
    Equal<T> &&
    requires(T a, T b) {
        { a <= b } -> bool;
        { a < b } -> bool;
        { a > b } -> bool;
        { a >= b } -> bool;
    };

Okay, let me try it out.

// conceptsDefinitionOrdering.cpp

#include <concepts>
#include <iostream>
#include <unordered_set>

template<typename T>
concept Equal =
    requires(T a, T b) {
        { a == b } -> std::convertible_to<bool>;
        { a != b } -> std::convertible_to<bool>;
    };


template <typename T>
concept Ordering =
    Equal<T> &&
    requires(T a, T b) {
        { a <= b } -> std::convertible_to<bool>;
        { a < b } -> std::convertible_to<bool>;
        { a > b } -> std::convertible_to<bool>;
        { a >= b } -> std::convertible_to<bool>;
    };

template <Equal T>
bool areEqual(T a, T b) {
    return a == b;
}

template <Ordering T>
T getSmaller(T a, T b) {
    return (a < b) ? a : b;
}
    
int main() {
  
    std::cout << std::boolalpha << std::endl;
  
    std::cout << "areEqual(1, 5): " << areEqual(1, 5) << std::endl;
  
    std::cout << "getSmaller(1, 5): " << getSmaller(1, 5) << std::endl;
  
    std::unordered_set<int> firSet{1, 2, 3, 4, 5};
    std::unordered_set<int> secSet{5, 4, 3, 2, 1};
  
    std::cout << "areEqual(firSet, secSet): " << areEqual(firSet, secSet) << std::endl;
  
    // auto smallerSet = getSmaller(firSet, secSet);
  
    std::cout << std::endl;
  
}

The function getSmaller requires, that both arguments a and b support the concept Ordering, and both have the same type. This requirement holds for the numbers 1 and 5. 

No alt text provided for this image

Of course, a std::unordered_set does not support ordering. The actual msvc compiler is very specific, when I try to compile the line auto smaller = getSmaller(firSet, secSet) with the flag /std:c++latest.

No alt text provided for this image

By the way. The error message is very clear: the associated constraints are not satisfied.

Of course, the concept Ordering is already part of the C++20 standard.

  • std::three_way_comparable: corresponds to my concept Ordering
  • std::three_way_comparable_with: allows the comparison of values of different type; e.g.: 1.0 < 1.0f

Maybe, you are irritated by the term three-way. With C++20, we get the three-way comparison operator, also known as the spaceship operator. <=>. Here is the first overview: C++20: The Core Language. I write about the three-way comparison operator in a future post. 

Compiler Support

I learn new stuff by trying it out. Maybe, you don't have an actual msvc available. In this case, use the current GCC (trunk) on the Compiler Explorer. GCC support the C++20 syntax for concepts. Here is the conceptsDefinitionOrdering.cpp for further experiments: https://godbolt.org/z/uyVFX8.  

What's next?

When you want to define a concrete type that works well in the C++ ecosystem, you should define a type that "behaves link an int". Such a concrete type could be copied and, the result of the copy operation is independent of the original one and has the same value. Formally, your concrete type should be a regular type. In the next post, I define the concepts Regular and SemiRegular.

Siegfried A. Hesker - Social Media Optimierung für Reichweite

Social Media Management für Unternehmen?? Optimierung Youtube, Instagram & Facebook Auftritte ?? Ich verwaltete Instagram- und FB-Seiten & baue Youtube Kan?le auf ...

5 年

??

回复

要查看或添加评论,请登录

Rainer Grimm的更多文章

社区洞察

其他会员也浏览了