C++ std::unique_ptr 存储在 std::map 中使用已删除的函数格式错误

C++ std::unique_ptr stored inside std::map use of deleted function ill formed

我有以下无法编译的代码,今天是星期五,我有点疲惫。

#include <string>
#include <memory>
#include <utility>
#include <map>

template< typename T, typename ...Args >
std::unique_ptr< T > make_unique( Args && ...args )
{
    return std::unique_ptr< T >( new T( std::forward< Args >( args )... ) );
}

struct A
{
};

std::map< std::string, std::unique_ptr< A > > _map = { { "A", make_unique< A >() } }; // <-- ERROR!!

下面编译没有问题

int main()
{
    std::pair< std::string, std::unique_ptr< A > > p { "B", make_unique< A >() };
    _map.insert( std::make_pair( "C", make_unique< A >() ) );
}

我得到的错误是(大致上,删除了 g++ 绒毛)

use of deleted function 'constexpr std::pair<...>( const st::pair<...> & )
'constexp std::pair<...>::pair( const std::pair<...> & ) is implicitly deleted because the default definition would be illegal.

啊!! 只需阅读 c++11 标准中的内容即可。

When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause

真可惜!!!

有人知道初始化列表是否完全不可能吗?

您对此无能为力:复制初始化列表中的元素。这不会与仅移动的 类 相处。

有一种方法可以绕过这个 "defect" 但它不太好读;你决定

using map_type  = std::map< std::string, std::unique_ptr< A > >;
using pair_type = map_type::value_type;
pair_type elements[] = { { "A", std::make_unique< A >() }, { "B", std::make_unique< A >() } };

map_type myMap { std::make_move_iterator( begin(elements) ), std::make_move_iterator( end(elements) ) };

这将使 myMap 遍历范围并在其中移动元素,而不是复制。方法来自 this 其他问题。