Разрешить неконстантным конвертировать в констант в шаблоне оболочки - PullRequest
0 голосов
/ 26 января 2012

Как можно разрешить неконстантную ссылку преобразовывать в константную ссылку в конструкторе копирования шаблона оболочки? Обратите внимание, что мой конструктор копирования является конструктором логического перемещения (до C ++ 11) - член init отслеживает, какая обертка в настоящее время допустима.

template<typename T>
class wrap 
{
    T & object;
    bool init;
public:
    wrap( T& object ) : object(object), init( true ) { }

    //attempt which fails since "init" is private in other type
    template<typename O>
    wrap( wrap<O> const & o )
        : object( o.object )
        , init( true )
    {
        const_cast<wrap<O>&>(o).init = false;
    }
};

Это прекрасно работает, если другой тип точно такой же, поскольку правила доступа разрешают доступ к закрытой переменной init. В основном, должно работать следующее:

//adding const
wrap<Type> a( get() );
wrap<Type const> b = a;

//base type would also be nice
wrap<BaseType> c = a;

Ответы [ 2 ]

1 голос
/ 26 января 2012

Подружитесь с другими специализациями:

template <typename U> friend class wrap;

или для лучшей инкапсуляции, просто их конструкторы преобразования:

template <typename U> template <typename O> 
friend wrap<U>::wrap(wrap<O> const &);

Было бы лучше объявить init mutable; при использовании const_cast существует риск неопределенного поведения, если кто-либо попытается скопировать объект const.

Также помните, что ваш шаблонный конструктор не будет перегружать неявно сгенерированный конструктор копирования. Вам также понадобится конструктор копирования для правильной работы с init:

wrap(wrap const & o) : object(o.object), init(true) {o.init = false;}
0 голосов
/ 26 января 2012

Хорошо, чтобы обойти ограничения доступа, вы можете просто добавить другие экземпляры wrap в друзья, поэтому добавьте template<typename U> friend class wrap; где-нибудь в теле класса. Таким образом, ваш пример должен скомпилироваться.

Однако вам не следует так лгать компилятору. Вы передаете o как const ref, обещая не менять его, а затем в любом случае изменить. Это нехорошо (или разрешено стандартом), поэтому компилятор может свободно нарушать ваш код любым способом. Вы действительно должны использовать const_cast для вызова функций, которые принимают аргументы как неконстантные, но которые не изменят сами аргументы (на ум приходит c apis). В этом случае я бы предложил объявить конструктор template<typename O> wrap(wrap<O>& o). Если вы действительно хотите принять это как постоянную ссылку, вы также можете пойти по пути объявления init как mutable, что означает, что его можно изменить, даже если объект const

Вы также должны заметить, что вы не объявляете конструктор копирования (хотя template<typename O> wrap( wrap<O> const & o ) может принять wrap<T>, он не считается, так что вам нужно определить это тоже, иначе для копирования в тот же тип будет использоваться сгенерированный компилятором конструктор копирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...