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:
first
and second
public fieldsfirst_type
and second_type
public inner typesfirst
== first_type
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?
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;
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With