我正在学习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
答案 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::emplace
与std::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") }
}
);