C++ Logo


Advanced search

Re: Question regarding how to declare templated functions inside a concept declaration

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Fri, 29 Apr 2022 01:24:14 +0100
On Thu, 28 Apr 2022 at 18:58, Marios Staikopoulos via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> I want to bring this back up – I did manage to get this working with an
> Archetype + the concept. But this seems so wrong – you basically must
> define a concept and then define a dummy class that constrains the
> template. This basically looks like a redundant declaration in code, and
> just adds more confusion.
> It seems like a hole if we cannot declare templated concept constraints
> inside of a concept – I can’t see a reason why this should be a limiting
> factor.
> This seems like a very realistic requirement for containers as well –
> something like the below:
> template<typename T>
> concept Iterator = requires() {
> …
> };
> template<typename T>
> concept Container = requires(T container, concept Iterator itr) {
> { container.begin() } -> std::same_as<Iterator>;
> { container.end() } -> std::same_as<Iterator>;
> };

This is not a problem; you can write { container.begin() } -> Iterator; and
{ container.end() } -> SentinelFor<decltype(container.begin())>; or
similar. Or use Same if you don't believe in sentinels.

> template<typename T>
> concept IterationAlgorithm = requires(T algo) {
> template<typename IT>
> requires Iterator<IT>
> { void apply(IT begin, IT end) } -> std::same_as<void>;
> };

There are difficulties. How will you prove to the compiler that every
operation that you use in (the declaration of) algo.apply (I assume apply
is intended to be a member function on T) is in fact present in the
Iterator concept? Even in your IterationAlgorithm you implictly require
that Iterator implies Movable, since you are passing the iterators by
value. But while std::input_or_output_iterator subsumes std::movable, that
does not tell the *compiler* that It is movable, since the Ro5 operation
concepts are expressed in terms of type traits, which to the compiler might
well have been partially specialized.

Even for constraints expressed entirely syntactically, there's a wider
problem which is that a compiler given the task of constructing archetypes
is *required* to do so in the laziest, most infuriatingly pettifogging way
possible, You specified that { cbuf.HasData() } -> std::same_as<bool>; for
cbuf T const, which is fine, but that doesn't say anything about being able
to call HasData on a T lvalue. Or a T or T const prvalue or xvalue. Or if
your Iterator is random-access and thus addable with int, then it's obvious
to humans that it should also be addable with unsigned, long etc., but not
to a compiler.

Received on 2022-04-29 00:24:26