# Concept template parameters

- Concept template parameters
- Concept template parameters 2

I thought I’d take a break from writing about `<=>`

and talk instead about Concepts. One of the things you cannot do with Concepts is use them as template parameters. Which means that you cannot compose concepts in any way except strictly using `&&`

or `||`

. This still gets a lot of good functionality, but I’ve run into a few situations where having a slightly better way of composing concepts would help out.

I thought I’d put a post together with some examples, as a way to work towards motivation for a language change. Towards higher-order concepts. This won’t be in C++20, but might be something we want to consider for C++23.

`AllOf`

In a previous post about how to do conditional spaceship, I pointed out that the key insight for doing this right is to ensure that `operator<=>`

is more constrained than `operator<`

. If `operator<`

is itself constrained, that ends up looking like this:

```
template <Cpp17LessThanComparable T>
bool operator<(vector<T> const&, vector<T> const&);
template <ThreeWayComparable T>
requires Cpp17LessThanComparable<T>
compare_3way_type_t<T>
operator<=>(vector<T> const&, vector<T> const&);
```

This works great, but is a a little awkward. Concepts have this built-in superpower of subsumption… but the problem here is that `ThreeWayComparable`

and `Cpp17LessThanComparable`

are totally unrelated, neither subsumes the other, so we need that extra repetitive `requires`

.

If we could just…

```
template <typename T, template <typename> concept... Cs>
concept AllOf = (Cs<T> && ...);
```

then we could:

```
template <Cpp17LessThanComparable T>
bool operator<(vector<T> const&, vector<T> const&);
template <AllOf<Cpp17LessThanComparable, ThreeWayComparable> T>
compare_3way_type_t<T>
operator<=>(vector<T> const&, vector<T> const&);
```

Now the question we have to answer is: how might this actually work?

If we reduce the scope to only allowing concept template parameters to be used on actual concept definitions, this question should be answerable. We know at the point of use of `AllOf<Cpp17LessThanComparable, ThreeWayComparable> T`

that is means precisely `Cpp17LessThanComparable<T> && ThreeWayComparable<T>`

. As such, we should know that this subsumes `Cpp17LessThanComparable<T>`

. Right?

We would also need this to work:

```
template <AllOf<Regular, ConvertibleTo<int>> T>
void foo(T );
```

`Regular`

is a unary concept, but `ConvertibleTo`

is binary. `ConvertibleTo<int>`

is a *partial-concept-id*, we’re used to seeing it in this context:

```
template <ConvertibleTo<int> T>
void foo(T );
```

In a way, `ConvertibleTo<int>`

behaves like a unary concept. As if we had a special concept like:

```
template <typename T>
concept ConvertibleToInt = ConvertibleTo<T, int>;
```

So we should be able to use *partial-concept_id*’s as unary concepts when it comes to unary concept template parameters. It seems fairly natural.

`Indirect`

Ranges introduces a bunch of function-related concepts into the standard library (see [concepts.callable]):

`Invocable<F, Args...>`

means you can`std::invoke()`

and`F`

with`Args...`

`RegularInvocable<F, Args...>`

is equivalent, and is just used as a marker in code to indicate that you can invoke`F`

multiple times`Predicate<F, Args...>`

means that`Invocable<F, Args...>`

and the result type is`Boolean`

(which is like`bool`

, mostly. Don’t look it up)`Relation<R, T, U>`

which is a slight generalization of`Predicate`

that works on all 2-type combinations.`StrictWeakOrder<R, T, U>`

which syntactically is just`Relation`

, but has additional semantic requires that the relation in question is a strict weak order.

Additionally, all of these concepts have “indirect” versions in [indirectcallable.indirectinvocable] - where instead of taking arguments, they take iterator types: `IndirectUnaryInvocable<F, I>`

, `IndirectRegularUnaryInvocable<F, I>`

, `IndirectUnaryPredicate<F, I>`

, `IndirectRelation<F, I, I2>`

, and `IndirectStrictWeakOrder<F, I, I2>`

. The definitions of these indirect concepts is lengthy (just about comparable to `Boolean`

):

```
template<class F, class I>
concept IndirectUnaryInvocable =
Readable<I> &&
CopyConstructible<F> &&
Invocable<F&, iter_value_t<I>&> &&
Invocable<F&, iter_reference_t<I>> &&
Invocable<F&, iter_common_reference_t<I>> &&
CommonReference<
invoke_result_t<F&, iter_value_t<I>&>,
invoke_result_t<F&, iter_reference_t<I>>>;
template<class F, class I>
concept IndirectRegularUnaryInvocable =
Readable<I> &&
CopyConstructible<F> &&
RegularInvocable<F&, iter_value_t<I>&> &&
RegularInvocable<F&, iter_reference_t<I>> &&
RegularInvocable<F&, iter_common_reference_t<I>> &&
CommonReference<
invoke_result_t<F&, iter_value_t<I>&>,
invoke_result_t<F&, iter_reference_t<I>>>;
template<class F, class I>
concept IndirectUnaryPredicate =
Readable<I> &&
CopyConstructible<F> &&
Predicate<F&, iter_value_t<I>&> &&
Predicate<F&, iter_reference_t<I>> &&
Predicate<F&, iter_common_reference_t<I>>;
template<class F, class I1, class I2 = I1>
concept IndirectRelation =
Readable<I1> && Readable<I2> &&
CopyConstructible<F> &&
Relation<F&, iter_value_t<I1>&, iter_value_t<I2>&> &&
Relation<F&, iter_value_t<I1>&, iter_reference_t<I2>> &&
Relation<F&, iter_reference_t<I1>, iter_value_t<I2>&> &&
Relation<F&, iter_reference_t<I1>, iter_reference_t<I2>> &&
Relation<F&, iter_common_reference_t<I1>,
iter_common_reference_t<I2>>;
template<class F, class I1, class I2 = I1>
concept IndirectStrictWeakOrder =
Readable<I1> && Readable<I2> &&
CopyConstructible<F> &&
StrictWeakOrder<F&, iter_value_t<I1>&, iter_value_t<I2>&> &&
StrictWeakOrder<F&, iter_value_t<I1>&, iter_reference_t<I2>> &&
StrictWeakOrder<F&, iter_reference_t<I1>, iter_value_t<I2>&> &&
StrictWeakOrder<F&, iter_reference_t<I1>,
iter_reference_t<I2>> &&
StrictWeakOrder<F&, iter_common_reference_t<I1>,
iter_common_reference_t<I2>>;
```

It’s lengthy… and very very repetitive. There’s a core common element to all of these concept definitions. A core common element that we cannot factor out. But, what if we could? What if we could declare a “function” that turned a “normal” concept into an “indirect” concept? That might look like this:

```
template <template <typename...> concept Direct,
typename F, typename... Is>
concept Indirect =
(Readable<Is> && ...) &&
CopyConstructible<F> &&
Direct<F&, iter_value_t<Is>&...> &&
Direct<F&, iter_reference_t<Is>...> &&
Direct<F&, iter_common_reference_t<Is>...> &&
CommonReference<
invoke_result_t<F&, iter_value_t<I>&...>,
invoke_result_t<F&, iter_reference_t<Is>...>>;
```

And we can use this concept “function” to give us the indirect versions without any repetition:

```
template<class F, class I>
concept IndirectUnaryInvocable =
Indirect<Invocable, F, I>;
template<class F, class I>
concept IndirectRegularUnaryInvocable =
Indirect<RegularInvocable, F, I>;
template<class F, class I>
concept IndirectUnaryPredicate =
Indirect<Predicate, F, I>;
template<class F, class I1, class I2 = I1>
concept IndirectRelation =
Indirect<Relation, F, I1, I2>;
template<class F, class I1, class I2 = I1>
concept IndirectStrictWeakOrder =
Indirect<StrictWeakOrder, F, I1, I2>;
```

I’d argue this is quite a bit clearer - it’s right there in the definition that `IndirectRelation`

is an `Indirect<Relation, ...>`

. It’s true that it was in the definition before, but it’s easier to read a one line definition than a seven-line one.

Now, to be fair, these aren’t *exactly* identical. My version of `IndirectStrictWeakOrder`

does not check that for mix-and-match cases like `StrictWeakOrder<F&, iter_value_t<I1>&, iter_reference_t<I2>>`

, whereas the wording in the Standard does. So to be perfectly apples-to-apples, I would have to create concept functions for both `Indirect`

and `Indirect2`

.

But that’s still a big improvement in usability.

`DecaysTo`

One thing people may get wrong is trying to use certain concepts with forwarding references:

```
template <Regular T>
void foo(T&&);
void bar(int i) {
foo(i); // error
}
```

This fails because we deduce `T`

as `int&`

and `int&`

is not `Regular`

. Now, maybe the intent of `foo()`

is to only allow rvalues, but that seems unlikely - the programmer probably wanted to write this business:

```
template <typename T>
requires Regular<decay_t<T>>
void foo(T&&);
```

But that’s kinda ugly. This’ll come up from time to time (dare I say, with some… `Regular`

ity) so it would be helpful to have nicer syntax for it. The current solution would be to define a special concept each time:

```
template <typename T>
concept DecaysToRegular = Regular<decay_t<T>>;
```

Unlike the `Indirect`

concepts, these are very easy to write and understand - they would all be one-liners. No problem. But it’s still a pretty unsatisfactory approach. It’d be nice to write something more general:

```
template <typename T, template <typename> concept C>
concept DecaysTo = C<decay_t<T>>;
```

which allows us to concisely express what we wanted all along:

```
template <DecaysTo<Regular> T>
void foo(T&&);
void bar(int i) {
foo(i); // ok!
}
```

Reads pretty nice, right?

A similar such use-case would be in writing concept *definitions*. For instance, the customization point object `std::ranges::begin`

checks for a `begin`

whose type decays to an `Iterator`

. Today you have to decay the left-hand side:

```
template <typename T>
concept member_begin = requires (T& t) {
{ decay_copy(t.begin()) } -> Iterator;
}
```

but maybe you could write it on the right-hand side instead. That is, where the concept actually belongs:

```
template <typename T>
concept member_begin = requires (T& t) {
{ t.begin() } -> DecaysTo<Iterator>;
}
```

There are a lot of these one-line metaconcepts that could come in handy. `RefersTo<C>`

, `IteratorTo<C>`

, `RangeOver<C>`

, and so forth. I’d rather write a one-line definition per metaconcept, not a one-line definition per metaconcept instantiation.

### Other motivating examples

If anyone else has interesting motivating examples of using concept template parameters to produce new concepts, I’d love to see them. By restricting ourselves to *only* having concept template parameters for concepts, we at least severely reduce the problem space we have to consider. Coming up with an answer for subsumption is easy when we’re not actually introducing any new variables.

Of course, there is at least one pretty great motivating use case for having concept template parameters for classes. An upgraded version of Louis Dionne’s dyno:

```
namespace std {
template <typename Sig>
using function = basic_any<Invocable<Sig>, sbo_storage<24>>;
template <typename Sig>
using function_ref = basic_any<Invocable<Sig>, non_owning_storage>;
template <typename Sig>
using any_invocable = basic_any<Invocable<Sig>, move_only_storage>;
}
```

But that’s a ways away. Let’s just worry about a better way to build up concepts.

*Next post in the series:*Concept template parameters 2

Let me know what you think of this article on twitter @BarryRevzin!