C++ 将常量右值绑定到右值引用

C++ 将常量右值绑定到右值引用,c++,c++11,smart-pointers,pass-by-rvalue-reference,C++,C++11,Smart Pointers,Pass By Rvalue Reference,在实现BS树的过程中,我注意到了一些我从开始使用C++11智能指针开始就不太确定的事情,这让我想知道为什么会这样。如果我使用init大括号对{}而不是括号,下面的代码就可以正常工作;我个人的规则是对每个成员进行值初始化(直接或通过一个ctor),因为Node::right和Node::left都是智能指针,所以它是空指针。 问题1:为什么括号失败而初始大括号对成功?仅在这种情况下,两者之间是否存在语义差异 在BST中,在接受std::initializer\u列表的ctor中,我知道std::i

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

在BST中,在接受std::initializer\u列表的ctor中,我知道std::initializer\u列表元素只能复制,根据。因此,如果我没有错的话,根据Scott Meyer在最近的GN13上的说法,对const对象执行移动只会触发该对象的复制

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

#包括
模板
结构体类型
{
//~std::unique_ptr left(nullptr),right(nullptr);
std::unique_ptr left{nullptr},right{nullptr};
节点*parent=nullptr;
T值{};
Node()=默认值;
节点(T&&val,节点*_left=nullptr,节点*_right=nullptr,
节点*_parent=nullptr):左(_left)、右(_right)、父(_parent),
值(标准::移动(val))
{
}
};
模板
结构二进制搜索树
{
std::唯一的_ptr根;
BinarySearchTree():根{nullptr}{}
BinarySearchTree(std::initializer_list&&lst):BinarySearchTree{}{
//如果以下代码更改为
//~for(auto&&i:lst){这将是一个错误
对于(typename std::remove_reference::type i:lst){
这->插入(std::move(i));
}
}
无效插入(T&v){}
};
int main(){
二元搜索树a{11,24};
返回0;
}
为什么括号失败而init括号对成功

因为圆括号用于函数声明。不能使用圆括号在类范围内初始化变量。即使
inti(1);
也不起作用

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

你的比较不公平。在
自动
版本中,你明确要求引用类型。在非
自动
版本中,你明确要求非引用类型。删除
&&
将使
自动
版本也起作用

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

auto&&
被推断为
const int&
,因为您无法更改
初始值设定项列表的内容:它的
begin()
end()
方法返回
const int*
。添加
std::move
不起作用,您不能像这样绕过
const

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

为什么括号失败而init括号对成功

因为圆括号用于函数声明。不能使用圆括号在类范围内初始化变量。即使
inti(1);
也不起作用

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

你的比较不公平。在
自动
版本中,你明确要求引用类型。在非
自动
版本中,你明确要求非引用类型。删除
&&
将使
自动
版本也起作用

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

auto&&
被推断为
const int&
,因为您无法更改
初始值设定项列表的内容:它的
begin()
end()
方法返回
const int*
。添加
std::move
不起作用,您不能像这样绕过
const

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

为什么括号失败而init括号对成功

因为圆括号用于函数声明。不能使用圆括号在类范围内初始化变量。即使
inti(1);
也不起作用

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

你的比较不公平。在
自动
版本中,你明确要求引用类型。在非
自动
版本中,你明确要求非引用类型。删除
&&
将使
自动
版本也起作用

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

auto&&
被推断为
const int&
,因为您无法更改
初始值设定项列表的内容:它的
begin()
end()
方法返回
const int*
。添加
std::move
不起作用,您不能像这样绕过
const

auto
将推断为
int
,即
#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;
}