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.