class A {
public:
explicit A(int x) {}
};
vector<A> v;
v.push_back(1); // compiler error since no implicit constructor
v.emplace_back(1); // calls explicit constructor
以上来自大卫·斯通(David Stone(的视频。我不明白的是为什么emplace_back
致电明确的构造函数?我在C 标准中看不到任何内容使这个合法。只有听过大卫·斯通的YouTube视频之后,我发现了这个。
现在,我尝试使用std::map
。
map<int, A> m;
m.insert(pair<int, A>(1, 2)); // compiler error since no implicit constructor
m.emplace(1, 2); // compiler error since no implicit constructor
为什么emplace
在这里失败?如果 emplace_back
可以呼叫显式构造函数,为什么emplace
不这样做?
emplace
方法通过用 placement new operator
将构造函数插入元素。在将其扩展到地图中时,您需要单独转发参数以构建密钥和价值。
m.emplace
(
::std::piecewise_construct // special to enable forwarding
, ::std::forward_as_tuple(1) // arguments for key constructor
, ::std::forward_as_tuple(2) // arguments for value constructor
);
emplace
函数调用您的构造函数,如http://eel.is/c draft/container.requirentess.general#15.5
T
是从args
进入X
的 CC_11,对于零或更多参数args
,表示以下表达式良好:
allocator_traits<A>::construct(m, p, args)
这意味着它最终取决于您的分配器。查看参考的意思,我们可以检查http://en.cppreference.com/w/cpp/memory/allocator_traits/constructs/construct
我们看到,如果分配器没有构造成员函数,或者是std::allocator
,则该调用等于
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
对于std::map<int, A>
,您表达式中的T
类型为std::pair<int const, A>
,args...
为1, 2
。因此,要知道您对emplace
的呼叫是否已良好,我们只需要决定对std::pair<int const, A>(1, 2)
的呼叫是否有效。因此,我们查看std::pair
的文档:http://en.cppreference.com/w/cpp/utility/pair/pair/pair
所讨论的构造函数被列为/*EXPLICIT*/ constexpr pair( const T1& x, const T2& y );
(假设C 17(。换句话说,就像调用一个常规函数,该函数接受int const &
作为第一个参数,而A const &
作为第二个参数。A
仅在int
中明确构造,因此您的呼叫不正确。emplace
调用仅在您直接构造的任何对象上从explicit
中保存您,在这种情况下,这只是std::pair
,而不是该类型的任何参数。
m.insert(std::pair<int, A>(1, 2))
编译,我不知道为什么它不为您编译。也许忘记了-std=c++11
标志?这是因为std::pair
构造函数将元素复制到first
和second
中时,将其显式调用构造函数。
如果要将其放置到std::map
中,则必须在std::pair
中指定键和值。您可以使用std::make_pair
:
m.emplace(std::make_pair(1, 2));
此编译,因为这对将在密钥/值对中构造,并且将调用显式构造函数。