C++20: Define the Concepts Equal and Ordering

Contents[Show]

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.

 

TimelineCpp20Concepts

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 areEqual(T 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.

haskellsTypeclasses

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 } -> std::convertible_to<bool>;
        { a < b } -> std::convertible_to<bool>;
        { a > b } -> std::convertible_to<bool>;
        { a >= b } -> std::convertible_to<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. 

equalAndOrdering

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.

equalAndOrderingError

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.

 

 

Thanks a lot to my Patreon Supporters: Meeting C++, Matt Braun, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Richard Ohnemus, Frank Grimm, Sakib, Broeserl, António Pina, Markus Falkner, Darshan Mody, Sergey Agafyin, Андрей Бурмистров, Jake, GS, and Lawton Shoemake.

 

Thanks in particular to:   crp4

 

   

Get your e-book at Leanpub:

The C++ Standard Library

 

Concurrency With Modern C++

 

Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages. I also included more than 120 source files.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more than 140 source files.

 

Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 700 pages full of modern C++ and more than 260 source files presenting concurrency in practice.

 

Get your interactive course

 

Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations
 
Tags: concepts

My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code

Visitors

Today 3648

All 3920258

Currently are 192 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments