Для новичков в C ++ часто довольно странно, что константные функции-члены могут вызывать неконстантные методы для объектов, на которые ссылается класс (либо по указателю, либо по ссылке). Например, следующее совершенно правильно:
class SomeClass
{
class SomeClassImpl;
SomeClassImpl * impl_; // PImpl idiom
public:
void const_method() const;
};
struct SomeClass::SomeClassImpl
{
void non_const_method() { /*modify data*/ }
};
void SomeClass::const_method() const
{
impl_->non_const_method(); //ok because impl_ is const, not *impl_
};
Однако иногда было бы весьма удобно, если бы константность распространялась на заостренные объекты (я добровольно использовал идиому PImpl, потому что это один из случаев, когда я думаю, что "распространение константности" было бы очень полезно).
При использовании указателей это может быть легко достигнуто с помощью какого-то интеллектуального указателя с операторами, перегруженными по константности:
template < typename T >
class const_propagating_ptr
{
public:
const_propagating_ptr( T * ptr ) : ptr_( ptr ) {}
T & operator*() { return *ptr_; }
T const & operator*() const { return *ptr_; }
T * operator->() { return ptr_; }
T const * operator->() const { return ptr_; }
// assignment operator (?), get() method (?), reset() method (?)
// ...
private:
T * ptr_;
};
Теперь мне просто нужно изменить SomeClass::impl_
на const_propagating_ptr<SomeClassImpl>
, чтобы получить требуемое поведение.
Итак, у меня есть несколько вопросов по этому поводу:
- Есть ли какие-то проблемы с распространением констант, которые я пропустил?
- Если нет, существуют ли библиотеки, предоставляющие классы для получения распространения константности?
- Разве не было бы полезно, чтобы обычные умные указатели (unique_ptr, shared_ptr и т. Д.) Предоставляли какое-то средство для получения такого поведения (например, через параметр шаблона)?