C++ Logo

std-discussion

Advanced search

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

From: Marios Staikopoulos <marios_at_[hidden]>
Date: Fri, 29 Apr 2022 18:47:52 +0000
I’m not sure if there is a misunderstanding, but the IterationAlgorithm concept, and other dependent concepts, need only to check that the function signatures are conforming to the requirements, not that they compile correctly – that error checking regarding movability and other constraints will happen during compilation normally, ie:

struct IterationAlgorithm_Impl
{
    template<Iterator T>
    void apply(T begin, T end) {
        // …. Do stuff here
    }
};

// Verify that our implementation satisfies the concept
static_assert(InterationAlgorithm<IterationAlgorithm_Impl>);

> 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.

In concept IterationAlgorithm, we don’t need to know that the code compiles correctly or satisfies the constraints at the declaration of the concept.. that isn’t its responsibility – its responsible only for verifying that the proper signatures required exist. In this case, all the IterationAlgorithm wants to check for is that there is a member function apply that takes in any Iterator concept as arguments.

Whether or not the apply() uses the constraints, and semantics of Iterator correctly will happen when IterationAlgorithm_Impl is compiled.

From: Edward Catmur <ecatmur_at_googlemail.com>
Sent: Thursday, April 28, 2022 5:24 PM
To: std-discussion_at_[hidden]
Cc: Marios Staikopoulos <marios_at_[hidden]>
Subject: Re: [std-discussion] Question regarding how to declare templated functions inside a concept declaration

On Thu, 28 Apr 2022 at 18:58, Marios Staikopoulos via Std-Discussion <std-discussion_at_[hidden]<mailto: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 18:47:57