Часто бывает сложно сбивать новичков С++, чтобы функции-члены-члены разрешали вызывать неконстантные методы для объектов, на которые ссылается класс (либо указателем, либо ссылкой). Например, совершенно правильно:
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, потому что это один из тех случаев, когда я думаю, что "распространение констант" было бы очень полезно).
При использовании указателей это может быть легко достигнуто с помощью какого-то умного указателя с перегруженными операторами на constness:
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>
, чтобы получить желаемое поведение.
Итак, у меня есть несколько вопросов по этому поводу:
- Есть ли некоторые проблемы с распространением constost, которые я упустил?
- Если нет, существуют ли библиотеки, которые предоставляют классы для получения распространения констант?
- Не было бы полезно, чтобы обычные интеллектуальные указатели (unique_ptr, shared_ptr и т.д.) обеспечивали некоторое значение для получения этого поведения (например, через параметр шаблона)?