STD :: MAP EMPLECE通过显式构造函数失败


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构造函数将元素复制到firstsecond中时,将其显式调用构造函数。

如果要将其放置到std::map中,则必须在std::pair中指定键和值。您可以使用std::make_pair

m.emplace(std::make_pair(1, 2));

此编译,因为这对将在密钥/值对中构造,并且将调用显式构造函数。

最新更新