Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a concept for Pair with C++20 concepts

To print any kind of std::pair we can implement the following method:

template<typename First, typename Second>
void printPair(const std::pair<First, Second>& p) {
    std::cout << p.first << ", " << p.second << std::endl;
}

But suppose we want to implement a method that can print a pair of any kind, not necessarily std::pair, based on the following requirements:

  • it has a first and second public fields
  • it has a first_type and second_type public inner types
  • type of first == first_type
  • type of second == second_type

Having a concept, let's call it Pair, could allow writing a method like:

void printPair(const Pair auto& p) {
    std::cout << p.first << ", " << p.second << std::endl;
}

How would such a concept be defined?

like image 699
Amir Kirsh Avatar asked Dec 14 '22 09:12

Amir Kirsh


1 Answers

There are some interesting subtleties here.

template<class P>
concept Pair = requires(P p) {
    typename P::first_type;
    typename P::second_type;
    p.first;
    p.second;
    requires std::same_as<decltype(p.first), typename P::first_type>;
    requires std::same_as<decltype(p.second), typename P::second_type>;
};

The first four lines are somewhat redundant, but can help produce better error messages. The remaining lines should be self-explanatory. Note that the use of decltype on a plain class member access produces the declared type of the data member.

The last two lines could also be written as

    { p.first } -> std::same_as<typename P::first_type&>;
    { p.second } -> std::same_as<typename P::second_type&>;

Here, the compound-requirement applies the type-constraint to decltype((p.first)). That expression is an lvalue, so the produced type is an lvalue reference type. Note that this version would accept both first_type first; and first_type& first;.

like image 62
T.C. Avatar answered Jan 14 '23 05:01

T.C.