简体   繁体   中英

Binding const rvalue to rvalue reference

While implementing a BS Tree, I noticed some things that I wasn't so sure about since I started using C++11 smart pointers and it makes me wonder why it is so. The code below works fine if I use init-brace pairs{} instead of the parentheses; my personal rule is to value initialize every member(directly or through a ctor) and since Node::right and Node::left are both smart pointers, therefore, nullptr it is. Question 1 : Why does the parentheses fail and init-brace pairs succeed? In this case ONLY, is there any semantic difference between the two?

In BST , in the ctor that takes an std::initializer_list, I understand that std::initializer_list elements are only copyable, according to this . So if I'm not wrong, according to Scott Meyer at the recent GN13, performing a move on a const object would only trigger the copy-ctor of the object.

Quesion 2 Why does the compiler fail to copy the object at the call to 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;
}

Why does the parentheses fail and init-brace pairs succeed?

Because parentheses are used for function declarations. You cannot use them to initialise variables at class scope. Even int i(1); won't work.

Why does the compiler fail to copy the object at the call to BST::insert( T&& ) ?

You're not being fair in your comparison. In your auto version, you explicitly ask for a reference type. In your non- auto version, you explicitly ask for a non-reference type. Removing the && would make the auto version work too.

Your insert method takes a T && . That's a non- const -qualified reference, so it cannot bind to any const object.

auto && is deduced to const int && , because you cannot change the contents of an initializer_list<int> : its begin() and end() methods return const int * . Adding std::move doesn't work, you cannot bypass const like that.

auto would deduce to int , and would work: you'd get a fresh non- const int local variable i , containing a copy of the value in the initialiser list. You can form non- const references to that local variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM