Можно сделать указатель на const. Вот этот ваш const, он относится к самому указателю, его нельзя менять (в смысле, на другой адрес). Но после разыменовывания получается не константная ссылка. Вот оно в
документации:
typename std::add_lvalue_reference<T>::type operator*() const
Там нет никакого const в типе возвращаемого значения, несмотря на то, что оператор можно вызывать у константных экземпляров класса. Зачем конкретно так сделано, я не знаю. Наверно, тут копируется поведение обычных указателей: там тоже можно иметь неизменный указатель на изменяемую область памяти.
Так что если вы хотите запретить менять объект, то можно сделать так:
void foo(const std::unique_ptr<const int>& ptr) {
if (ptr) {
*ptr += 5; // Ошибка компиляции.
std::cout << *ptr;
}
}
int main() {
std::unique_ptr<const int> ptr = std::make_unique<const int>(5);
foo(ptr);
}
Правда, придется писать много лишнего кода, если будете передавать неконстантный объект внутрь функции, которая хочет ссылку на константный.
Но вообще, обычно нет смысла передавать unique_ptr по ссылке. Можно передать по ссылке сам объект, все равно владение в функцию не передается же. И уже там можно навешивать const, если надо. Или, если передавать просто unique_ptr, без ссылки, то даже лишнего кода не надо для обработки const:
void foo(const std::unique_ptr<const int> ptr) {
}
int main() {
std::unique_ptr<int> ptr = std::make_unique<int>(5);
foo(std::move(ptr));
}