std :: map \ templates使用显式构造函数失败

时间:2017-04-16 07:07:27

标签: c++ c++11

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的video。我无法理解的是emplace_back为什么要打电话 显式构造函数?我在C ++标准中没有看到任何内容 使这个合法化。只有在收听David Stone的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没有做同样的事情?

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

emplace函数调用您的构造函数,如http://eel.is/c++draft/container.requirements.general#15.5标准中所述

  

T EmplaceConstructibleX args args,对于零个或多个参数allocator_traits<A>::construct(m, p, args),意味着以下表达式格式正确:

     

std::allocator

这意味着它最终归结为你的分配器。查看该调用的参考意义,我们可以查看http://en.cppreference.com/w/cpp/memory/allocator_traits/construct

我们看到如果分配器没有构造成员函数,或者它是::new (static_cast<void*>(p)) T(std::forward<Args>(args)...),那么调用等同于

std::map<int, A>

对于T,表达式中的std::pair<int const, A>类型为args...1, 2emplace。因此,要知道您对std::pair<int const, A>(1, 2)的调用是否格式正确,我们只需要确定对std::pair的调用是否有效。因此,我们会查看/*EXPLICIT*/ constexpr pair( const T1& x, const T2& y );http://en.cppreference.com/w/cpp/utility/pair/pair

的文档

有问题的构造函数列为int const &(假设是C ++ 17)。换句话说,它就像调用一个接受A const &作为第一个参数并且A作为第二个参数的常规函数​​。 int只能从emplace明确构建,因此您的调用是不正确的。 explicit调用仅在std::pair上保存您正在构建的任何对象,在这种情况下只是{{1}},而不是该类型的任何参数。

答案 2 :(得分:1)

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

这会编译,因为该对将在键/值对中构造到位,并且将调用显式构造函数。