允许非const在包装器模板中转换为const

时间:2012-01-26 15:16:29

标签: c++ templates

如何在包装器模板复制构造函数中允许非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;

2 个答案:

答案 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>它不计算,因此您也需要定义它,或者复制到相同类型将使用编译器生成的复制构造函数。