Кажется невозможным защитить std::unique_ptr
от модификации, сделав его const
в std::experimental::propagate_const
, но чтобы понять почему, нам нужно go через исходный код std::experimental::propagate_const
, он доступен на пропагат_конст .
propagate_const
имеет закрытую переменную,
private:
_Tp _M_t;
Поэтому, когда вы создаете объект std::experimental::propagate_const<const std::unique_ptr<X>> m_ptrX;
, здесь _Tp
является параметром шаблона, и это приведет к _Tp = const std::unique_ptr<X>
Теперь об ошибке сообщается в m_ptr->g();
строке void Y::f()
, неконстантная перегрузка f
, поэтому давайте go пройдем через все вызовы функций propagate_const
.
Итак, m_ptr->g()
делает вызов неконстантным operator->()
из propagate_const
и который имеет следующую реализацию,
constexpr element_type* operator->(){
return get();
}
Затем он вызывает get()
, неконстантную перегрузку, потому что operator->()
само по себе не является постоянной перегрузкой, теперь get()
имеют следующую реализацию,
constexpr element_type* get(){
return __to_raw_pointer(_M_t);
}
Наконец, __to_raw_pointer
является закрытой функцией шаблона propagate_const
и имеет следующие перегрузки,
template <typename _Up> static constexpr element_type* __to_raw_pointer(_Up* __u) { return __u; }
template <typename _Up> static constexpr element_type* __to_raw_pointer(_Up& __u) { return __u.get(); }
template <typename _Up>static constexpr const element_type* __to_raw_pointer(const _Up* __u) { return __u; }
template <typename _Up> static constexpr const element_type* __to_raw_pointer(const _Up& __u) { return __u.get(); }
Поскольку тип закрытого элемента данных _M_t
равен const std::unique_ptr<X>
и из-за этого __to_raw_pointer(_M_t)
выберет последнюю перегрузку, то есть
template <typename _Up>
static constexpr const element_type* __to_raw_pointer(const _Up& __u) {
return __u.get();
}
Так что это источник ошибки, тип возвращаемого значения const element_type*
, который будет выведен на const X*
, но не постоянная перегрузка get()
constexpr element_type* get() {
return __to_raw_pointer(_M_t);
}
имеет тип возврата element_type*
, который будет выведен на X*
. Понятно, что const X*
не может конвертироваться в X*
, и это именно та ошибка, о которой сообщают.
Так что std::experimental::propagate_const<const std::unique_ptr<X>> m_ptrX;
не будет работать.