C++ 映射大括号初始化和唯一指针
C++ map brace initialization and unique ptr
为什么我不能在 unique_ptr 中使用地图的大括号初始化?
编辑:我在 c++17 模式下使用 gcc 7.2。
我可以使用 make_pair 和 [] 运算符创建并插入无序映射。
std::unordered_map<std::string, std::unique_ptr<A>> map;
map.insert(std::make_pair("hello",std::make_unique<A>()));
map["foo"] = std::make_unique<A>();
但我不明白为什么在使用大括号时会失败。
map.insert({"foo", std::make_unique<A>()}); // Error
error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&)
自 C++11 起,关联容器插入需要 copy-costructible 左值或 move-insertable 可变右值。因此,像您一样调用 insert()
和 make_pair()
没有问题:后者构造一个 pair<const char[],unique_ptr>
用于初始化 value_type
右值。
大括号初始化的问题是(直到 C++17)value_type const& 重载得到首选(因为没有合适的 value_type&& 重载),因此需要一个副本并且出现错误。
确实,请注意,这两种形式都在 gcc trunk 和 clang 5(使用 libc++)中以 c++17 模式编译。
更准确地说,从 C++11 开始,相关的插入语义要求改为
[unord.req] If t is a non-const rvalue expression, value_type shall be MoveInsertable into X; otherwise, value_type shall be CopyInsertable into X.
是实际成员规范,但有所不同;直到 C++17,我们有:
pair<iterator, bool> insert(const value_type& obj);
template <class P> pair<iterator, bool> insert(P&& obj);
...
其中泛型重载被 SFINAE 限制为 std::is_constructible<value_type, P&&>::value
。显然,使用 braced-init-list 将 select const& 在这里重载(注意:还有一个 initializer_list 重载,但它不适用于 OP例)。
相反,在 C++17 中我们还有
pair<iterator, bool> insert(value_type&& obj);
为什么我不能在 unique_ptr 中使用地图的大括号初始化?
编辑:我在 c++17 模式下使用 gcc 7.2。
我可以使用 make_pair 和 [] 运算符创建并插入无序映射。
std::unordered_map<std::string, std::unique_ptr<A>> map;
map.insert(std::make_pair("hello",std::make_unique<A>()));
map["foo"] = std::make_unique<A>();
但我不明白为什么在使用大括号时会失败。
map.insert({"foo", std::make_unique<A>()}); // Error
error: use of deleted function ‘std::pair<_T1, _T2>::pair(const std::pair<_T1, _T2>&)
自 C++11 起,关联容器插入需要 copy-costructible 左值或 move-insertable 可变右值。因此,像您一样调用 insert()
和 make_pair()
没有问题:后者构造一个 pair<const char[],unique_ptr>
用于初始化 value_type
右值。
大括号初始化的问题是(直到 C++17)value_type const& 重载得到首选(因为没有合适的 value_type&& 重载),因此需要一个副本并且出现错误。
确实,请注意,这两种形式都在 gcc trunk 和 clang 5(使用 libc++)中以 c++17 模式编译。
更准确地说,从 C++11 开始,相关的插入语义要求改为
[unord.req] If t is a non-const rvalue expression, value_type shall be MoveInsertable into X; otherwise, value_type shall be CopyInsertable into X.
是实际成员规范,但有所不同;直到 C++17,我们有:
pair<iterator, bool> insert(const value_type& obj);
template <class P> pair<iterator, bool> insert(P&& obj);
...
其中泛型重载被 SFINAE 限制为 std::is_constructible<value_type, P&&>::value
。显然,使用 braced-init-list 将 select const& 在这里重载(注意:还有一个 initializer_list 重载,但它不适用于 OP例)。
相反,在 C++17 中我们还有
pair<iterator, bool> insert(value_type&& obj);