Это интересный вопрос, хотя, честно говоря, у меня такое ощущение, что вы подходите к вопросу с некоторыми ложными посылками.
Во-первых, «универсальный» не означает, что универсальный код должен работать для любого типа T
, который может существовать. Напротив, универсальный код обычно говорит вам, каковы требования к T
, чтобы заставить код делать то, что он должен делать.
Например, T
должно быть CopyAssignable и CopyConstructible, иначе вы не можете создать экземпляр std::vector<T>
. T
должен быть разрушаем, иначе вы не можете создать экземпляр std::optional<T>
. И т. Д.
Seoncd, большинство const
на самом деле относится к тому, как используется экземпляр (в отличие от того, чем на самом деле является экземпляр).
В качестве примера рассмотрим
template <typename T>
void print(const T& t) {
std::cout << t;
}
Этот шаблон может быть создан только в том случае, если существует перегрузка operator<<
, которая принимает const T&
. Теперь, если тип не выполняет это требование, вы не можете создать экземпляр метода для этого типа.
Обратите внимание, что если какой-то тип Foo
нарушает это требование, имея только
std::ostream& operator<<(std::ostream&, Foo&);
удаление const
из print
не является решением, потому что тогда внезапно было бы невозможно вызвать print
с любым другим const T&
. Заявление о том, что print не изменяет свои параметры, является полностью допустимым использованием const
в шаблонном коде.