Требуйте в концептах шаблона только существенные свойства
Причина
Сохранять интерфейсы простыми и стабильными.
Пример
Рассмотрим sort с упрощённой поддержкой отладки:
void sort(sortable auto& s) // сортирует последовательность s
{
if (debug) cerr << "enter sort( " << s << ")\n";
// ...
if (debug) cerr << "exit sort( " << s << ")\n";
}
Стоит ли переписать это так:
template<sortable S>
requires Streamable<S>
void sort(S& s) // сортирует последовательность s
{
if (debug) cerr << "enter sort( " << s << ")\n";
// ...
if (debug) cerr << "exit sort( " << s << ")\n";
}
В конце концов, sortable не требует поддержки iostream. С другой стороны, в фундаментальной идее сортировки нет ничего, связанного с отладкой.
Примечание
Если требовать перечисления всех используемых операций среди требований, интерфейс становится нестабильным: каждый раз, когда мы изменяем средства отладки, сбор данных об использовании, поддержку тестирования, обработку ошибок и т. д., определение шаблона должно меняться, и каждое использование шаблона придётся перекомпилировать. Это неудобно, а в некоторых средах — неосуществимо.
Напротив, если мы используем в реализации операцию, не гарантированную проверкой концепта, мы можем получить позднюю ошибку времени компиляции.
Отказываясь от проверки концепта для свойств аргумента шаблона, не считающихся существенными, мы откладываем проверку до времени инстанцирования. Мы считаем это приемлемым компромиссом.
Обратите внимание, что использование не-локальных, не-зависимых имён (таких как debug и cerr) также создаёт зависимости от контекста, которые могут привести к «таинственным» ошибкам.
Примечание
Бывает сложно решить, какие свойства типа являются существенными, а какие — нет.
Контроль
???