Связанные типы?
Как вы знаете, T*
и const T*
являются связанными типами.Существует стандартное преобразование из первого во второе (квалификационное преобразование).
Во-первых, вы должны понимать, что A<T>
и A<const T>
не относятся к общим типам.Эти типы могут иметь разный размер, представление и назначение.Один может быть определен, но не другой.
В частности, A<const T>
не является константной квалификацией A<T>
, поэтому между ними нет квалификационного преобразования, и C ++ недостаточно гибок, чтобы объявить пользователяопределяемые квалификации-конверсии.(Пользователь не может объявить любое стандартное преобразование, только пользовательское преобразование - пользовательское преобразование не является стандартным преобразованием.)
Таким образом, пользовательские типы принципиально отличаются от фундаментальных типов: онине могут быть связаны с фундаментальными типами.
shared_ptr<>
shared_ptr<>
предназначен для формирования семейства совместимых типов: shared_ptr<T>
неявно преобразуется в shared_ptr<U>
тогда T*
неявно конвертируется в U*
.В частности, shared_ptr<T>
неявно преобразуется в shared_ptr<const T>
.Он также неявно преобразуется в shared_ptr<void>
, по той же причине.
Поскольку типы shared_ptr<const T>
и shared_ptr<T>
не связаны каким-либо особым образом, преобразование из shared_ptr<T>
в shared_ptr<const T>
не являетсяотличается от shared_ptr<T>
до shared_ptr<void>
.Это всего лишь два разных преобразования, но ни одно из них не может считаться «предпочтительным» в любом контексте, в отличие от преобразования из T*
в const T*
(rank = Exact match), которое предпочтительнее, чем преобразование из T*
в void*
(rank = Conversion).
Шаблоны функций
Некоторые стандартные преобразования разрешены для аргументов функции выведенных шаблонов:
- квалификационных преобразований
- некоторых преобразователей указателей: производное-к-основанию
- ...
Но, как мы видели, между shared_ptr<>
типами таких преобразований не существует.
Это означает, что дажеесли компилятору было разрешено перечислять все возможные типы для параметра шаблона, чтобы превратить шаблон функции
template <typename V>
void f (shared_ptr<const T> v1);
в бесконечный набор прототипов функций:
for every type T,
such that shared_ptr<const T> can be instantiated:
f (shared_ptr<const T>)
, если у вас нет точногосоответствовать, вы не сможете вызвать функцию: учитывая объявления
struct Base {};
struct Derived : Base {};
shared_ptr<Derived> d;
среди множества f
прототипов, есть:
f (shared_ptr<const Base>)
f (shared_ptr<const Derived>)
, поэтому вызов f (d)
шможет быть неоднозначным, поскольку оба этих кандидата включают в себя различные пользовательские преобразования.