【问题标题】:Allow a non-const to convert to const in a wrapper template允许非常量在包装模板中转换为 const
【发布时间】:2012-01-26 15:16:29
【问题描述】:

如何允许非常量引用在包装模板复制构造函数中转换为 const 引用?请注意,我的复制构造函数是一个逻辑移动构造函数(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;

【问题讨论】:

  • “如果另一种类型完全相同,这可以正常工作” - 实际上,它没有。这将使用隐式复制构造函数,而不是模板,因此两者都将以 init 结束。

标签: c++ templates


【解决方案1】:

结交其他专业:

template <typename U> friend class wrap;

或者为了更好的封装,只是它们的转换构造函数:

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

最好声明initmutable;使用const_cast,如果有人试图复制const 对象,则存在未定义行为的风险。

另外,请注意您的构造函数模板不会重载隐式生成的复制构造函数。您还需要一个复制构造函数来使用init 做正确的事情:

wrap(wrap const & o) : object(o.object), init(true) {o.init = false;}

【讨论】:

  • 这行得通,但你能解释一下第二个的疯狂语法吗?为什么我需要两个模板部分?
  • @edA-qamort-ora-y:因为它指的是类模板中的函数模板;每个人都需要一个template
【解决方案2】:

为了绕过访问限制,您可以简单地将wrap 的其他实例添加为朋友,因此在类主体的某处添加template&lt;typename U&gt; friend class wrap;。这样你的例子应该编译。

但是你真的不应该那样对编译器撒谎。您将o 传递为const ref,承诺不更改它,然后无论如何都要更改它。这不好(或标准允许),因此编译器可以随意以各种方式破坏您的代码。你真的应该使用const_cast 来调用将参数作为非常量但不会改变参数本身的函数(想到c apis)。在这种情况下,我建议将构造函数声明为template&lt;typename O&gt; wrap(wrap&lt;O&gt;&amp; o)。如果你真的想把它当作 const 引用,你也可以将init 声明为mutable,这意味着即使对象是const 也可以修改它

您还应该注意,您没有声明复制构造函数(即使template&lt;typename O&gt; wrap( wrap&lt;O&gt; const &amp; o ) 可以接受wrap&lt;T&gt;这不算,所以您也需要定义它,否则复制到相同类型将使用编译器生成复制构造函数。

【讨论】:

    猜你喜欢
    • 2018-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 2021-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多