【问题标题】:How to inplace construct std::map<int, std::array<Class, 2>>?如何就地构造 std::map<int, std::array<Class, 2>>?
【发布时间】:2019-07-28 06:56:33
【问题描述】:

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

std::map emplace without copying value

我尝试了一个示例类,在该类中我删除了复制构造函数并只允许移动。地图看起来像std::map&lt;int, std::array&lt;Class, 2&gt;&gt; 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

【问题讨论】:

标签: c++ c++11 stl


【解决方案1】:
std::forward_as_tuple(
        Class{ 10, std::string("ten") },   // here is the problem
        Class{ 20, std::string("twenty") }
    )

您将传递给 std::array 构造函数 2 个 Class 类型的对象,而不是您应该传递一个包含 2 个对象的数组

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

【讨论】:

  • 这不是“包含 2 个对象的数组”,而是初始化列表。
【解决方案2】:

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") }
        }
    );

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多