【问题标题】:Binding const rvalue to rvalue reference将 const rvalue 绑定到 rvalue 引用
【发布时间】:2014-09-13 06:54:00
【问题描述】:

在实现 BS 树时,我注意到了一些自从我开始使用 C++11 智能指针以来我不太确定的事情,这让我想知道为什么会这样。如果我使用 init-brace pairs{} 而不是括号,下面的代码可以正常工作;我个人的规则是初始化每个成员(直接或通过一个ctor),因为 Node::rightNode::left 都是因此,智能指针是 nullptr问题 1:为什么括号失败而 init-brace 对成功?仅在这种情况下,两者之间是否存在语义差异?

BST 中,根据this,在采用 std::initializer_list 的 ctor 中,我知道 std::initializer_list 元素只能复制。因此,如果我没记错的话,根据最近 GN13 上的 Scott Meyer 的说法,对 const 对象执行移动只会触发对象的 copy-ctor。

问题 2 为什么编译器无法在调用 BST::insert( T&& ) 时复制对象?

#include <memory>

template<typename T>
struct Node
{

    //~ std::unique_ptr<Node<T>> left ( nullptr ), right ( nullptr );
    std::unique_ptr<Node<T>> left { nullptr }, right { nullptr };
    Node<T> *parent = nullptr;
    T value { };
    Node<T> () = default;
    Node<T> ( T && val, Node<T> * _left = nullptr, Node<T> *_right = nullptr,
          Node<T> *_parent = nullptr ): left( _left ), right ( _right ), parent( _parent ),
                                        value ( std::move( val ) )
        {

        }
};
template<typename T>
struct BinarySearchTree
{
    std::unique_ptr<Node<T>> root;

    BinarySearchTree(): root { nullptr } { }
    BinarySearchTree( std::initializer_list<T> && lst ): BinarySearchTree { }{
    //If the below code were changed to
    //~ for( auto && i: lst ){ it would be an error
        for( typename std::remove_reference<typename std::remove_const<T>::type>::type i: lst ){
            this->insert( std::move( i ) );
        }
    }
    void insert( T && v ) { }
};

int main(){
    BinarySearchTree<int> a { 11, 24 };

    return 0;
}

【问题讨论】:

    标签: c++ c++11 smart-pointers pass-by-rvalue-reference


    【解决方案1】:

    为什么括号失败而初始化大括号对成功?

    因为括号用于函数声明。您不能使用它们在类范围内初始化变量。即使int i(1); 也行不通。

    为什么编译器在调用 BST::insert( T&& ) 时无法复制对象?

    你的比较不公平。在您的 auto 版本中,您明确要求引用类型。在您的非auto 版本中,您明确要求非引用类型。删除&amp;&amp; 将使auto 版本也可以工作。

    您的insert 方法采用T &amp;&amp;。这是一个非const 限定的引用,因此它不能绑定到任何const 对象。

    auto &amp;&amp; 被推导出为const int &amp;&amp;,因为您无法更改initializer_list&lt;int&gt; 的内容:它的begin()end() 方法返回const int *。加std::move不行,不能这样绕过const

    auto 会推导出为int,并且会起作用:你会得到一个新的非const int 局部变量i,其中包含初始化列表中值的副本。您可以形成对该局部变量的非const 引用。

    【讨论】:

      猜你喜欢
      • 2017-10-31
      • 2021-09-17
      • 2020-07-20
      • 1970-01-01
      • 2011-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多