如何在包装器模板复制构造函数中允许非const引用转换为const引用?请注意,我的复制构造函数是一个逻辑移动构造函数(pre-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;
答案 0 :(得分:1)
与其他专业人士保持联系:
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;}
答案 1 :(得分:0)
为了解决访问限制,您可以简单地将wrap
的其他实例添加为朋友,因此在类的主体中的某处添加template<typename U> friend class wrap;
。那样你的例子应该编译。
但是你真的不应该这样对编译器撒谎。您将o
作为const ref
传递,承诺不会更改它,然后无论如何都要更改它。这不好(或标准允许),因此编译器可以随意以各种方式破坏您的代码。你真的应该使用const_cast
来调用函数,这些函数将参数作为非常量,但不会改变参数本身(c apis浮现在脑海中)。在这种情况下,我建议将构造函数声明为template<typename O> wrap(wrap<O>& o)
。如果你真的想把它当作const引用,你也可以将init
声明为mutable
,这意味着即使对象是const
您还应注意,您没有声明复制构造函数(即使template<typename O> wrap( wrap<O> const & o )
可以接受wrap<T>
它不计算,因此您也需要定义它,或者复制到相同类型将使用编译器生成的复制构造函数。