Require only essential properties in a template's concepts
Reason
Keep interfaces simple and stable.
Example
Consider, a sort instrumented with (oversimplified) simple debug support:
void sort(sortable auto& s) // sort sequence s
{
if (debug) cerr << "enter sort( " << s << ")\n";
// ...
if (debug) cerr << "exit sort( " << s << ")\n";
}
Should this be rewritten to:
template<sortable S>
requires Streamable<S>
void sort(S& s) // sort sequence s
{
if (debug) cerr << "enter sort( " << s << ")\n";
// ...
if (debug) cerr << "exit sort( " << s << ")\n";
}
After all, there is nothing in sortable that requires iostream support. On the other hand, there is nothing in the fundamental idea of sorting that says anything about debugging.
Note
If we require every operation used to be listed among the requirements, the interface becomes unstable: Every time we change the debug facilities, the usage data gathering, testing support, error reporting, etc., the definition of the template would need change and every use of the template would have to be recompiled. This is cumbersome, and in some environments infeasible.
Conversely, if we use an operation in the implementation that is not guaranteed by concept checking, we might get a late compile-time error.
By not using concept checking for properties of a template argument that is not considered essential, we delay checking until instantiation time. We consider this a worthwhile tradeoff.
Note that using non-local, non-dependent names (such as debug and cerr) also introduces context dependencies that might lead to "mysterious" errors.
Note
It can be hard to decide which properties of a type are essential and which are not.
Enforcement
???