如何替换构造std :: map <int,std :: array <Class,2 >>?

时间:2019-07-28 06:56:33

标签: c++ c++11 stl

我正在学习std::map的就地构造,并找到了使用emplace and std::piecewise_construct, std::forward_as_tuple的解决方案。

std::map emplace without copying value

我用一个示例类进行了尝试,在该类中,我删除了复制构造函数,只允许移动。地图看起来像std::map<int, std::array<Class, 2>> myMap;

#include <iostream>
#include <string>
#include <map>
#include <tuple>
#include <array>

class Class
{
    int m_var;
    std::string m_str;
public:
    Class(int var, const std::string& str) : m_var(var), m_str(str)
    {
        std::cout << "Cont'r called...\n";
    }
    Class(const Class&) = delete;
    Class& operator=(const Class&) = delete;
    Class(Class&& other) :m_var(std::move(other.m_var)), m_str(std::move(other.m_str))
    {
        std::cout << "Move called...\n";
    }
    Class& operator=(Class&& other)
    {
        this->m_var = std::move(other.m_var);
        this->m_str = std::move(other.m_str);
        std::cout << "Move= called...\n";
        return *this;
    }
};

using Value = std::array<Class, 2>;
int main()
{
    std::map<int, Value> myMap;
    // create in place the objects
    myMap.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(1),
        std::forward_as_tuple(
            Class{ 10, std::string("ten") },   // here is the problem
            Class{ 20, std::string("twenty") }
        )
    );

    return 0;
}

但这给了我很多错误,我无法理解。 您能告诉我我在这里做错了什么吗? 我正在使用C ++ 11

谢谢!

In file included from /opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/stl_map.h:63:0,
                 from /opt/wandbox/gcc-6.3.0/include/c++/6.3.0/map:61,
                 from prog.cc:3:
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/tuple: In instantiation of 'std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {int&&}; long unsigned int ..._Indexes1 = {0ul}; _Args2 = {Class&&, Class&&}; long unsigned int ..._Indexes2 = {0ul, 1ul}; _T1 = const int; _T2 = std::array<Class, 2ul>]':
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/tuple:1575:63:   required from 'std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {int&&}; _Args2 = {Class&&, Class&&}; _T1 = const int; _T2 = std::array<Class, 2ul>]'
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/ext/new_allocator.h:120:4:   required from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const int, std::array<Class, 2ul> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<Class&&, Class&&>}; _Tp = std::_Rb_tree_node<std::pair<const int, std::array<Class, 2ul> > >]'
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/alloc_traits.h:455:4:   required from 'static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const int, std::array<Class, 2ul> >; _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<Class&&, Class&&>}; _Tp = std::_Rb_tree_node<std::pair<const int, std::array<Class, 2ul> > >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::_Rb_tree_node<std::pair<const int, std::array<Class, 2ul> > > >]'
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/stl_tree.h:543:32:   required from 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_construct_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<Class&&, Class&&>}; _Key = int; _Val = std::pair<const int, std::array<Class, 2ul> >; _KeyOfValue = std::_Select1st<std::pair<const int, std::array<Class, 2ul> > >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::array<Class, 2ul> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const int, std::array<Class, 2ul> > >*]'
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/stl_tree.h:560:4:   required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<Class&&, Class&&>}; _Key = int; _Val = std::pair<const int, std::array<Class, 2ul> >; _KeyOfValue = std::_Select1st<std::pair<const int, std::array<Class, 2ul> > >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::array<Class, 2ul> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const int, std::array<Class, 2ul> > >*]'
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/stl_tree.h:2149:64:   required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_unique(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<Class&&, Class&&>}; _Key = int; _Val = std::pair<const int, std::array<Class, 2ul> >; _KeyOfValue = std::_Select1st<std::pair<const int, std::array<Class, 2ul> > >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::array<Class, 2ul> > >]'
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/stl_map.h:559:64:   required from 'std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::emplace(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<int&&>, std::tuple<Class&&, Class&&>}; _Key = int; _Tp = std::array<Class, 2ul>; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, std::array<Class, 2ul> > >; typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<std::pair<const _Key, _Tp> >::other>::iterator = std::_Rb_tree_iterator<std::pair<const int, std::array<Class, 2ul> > >]'
prog.cc:43:2:   required from here
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/tuple:1586:70: error: no matching function for call to 'std::array<Class, 2ul>::array(Class, Class)'
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
                                                                      ^
In file included from /opt/wandbox/gcc-6.3.0/include/c++/6.3.0/tuple:39:0,
                 from /opt/wandbox/gcc-6.3.0/include/c++/6.3.0/bits/stl_map.h:63,
                 from /opt/wandbox/gcc-6.3.0/include/c++/6.3.0/map:61,
                 from prog.cc:3:
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/array:90:12: note: candidate: std::array<Class, 2ul>::array(std::array<Class, 2ul>&&)
     struct array
            ^~~~~
/opt/wandbox/gcc-6.3.0/include/c++/6.3.0/array:90:12: note:   candidate expects 1 argument, 2 provided

2 个答案:

答案 0 :(得分:3)

std::forward_as_tuple(
        Class{ 10, std::string("ten") },   // here is the problem
        Class{ 20, std::string("twenty") }
    )

您要向std::array构造函数发送Class类型的2个对象,而应该传递包含2个对象的数组

std::forward_as_tuple(
        { // !!
        Class{ 10, std::string("ten") },   // no problem here
        Class{ 20, std::string("twenty") }
         } // !!
    )

答案 1 :(得分:1)

std::array仅具有隐式构造函数,因此必须通过聚合初始化进行声明。

map::emplacestd::piecewise_construct的作用类似于

// here is the problem: using ()
std::array<Class, 2> arr(Class{ 10, std::string("ten") },
                         Class{ 20, std::string("twenty") });

您需要的地方:

// No problem using {}
std::array<Class, 2> arr{Class{ 10, std::string("ten") },
                         Class{ 20, std::string("twenty") }};

解决方法是直接传递std::array

myMap.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(1),
        std::forward_as_tuple(
        std::array<Class, 2>{
            Class{ 10, std::string("ten") },
            Class{ 20, std::string("twenty") }
        }
        )
    );

但是在当前情况下,您不再需要std::piecewise_construct

myMap.emplace(
        1,
        std::array<Class, 2>{
            Class{ 10, std::string("ten") },
            Class{ 20, std::string("twenty") }
        }
    );