【问题标题】:emplace and default constructors [duplicate]安置和默认构造函数[重复]
【发布时间】:2019-01-27 13:00:06
【问题描述】:

鉴于以下代码,我很惊讶try_emplace 无法使用主函数第一行中演示的默认构造函数,而是抱怨没有对Element::Element(double, double) 的匹配函数调用。我是否误解了编译器创建默认构造函数的方式或try_emplace 的用法?我当然可以通过为Element 定义一个所有参数ctors 来让这段代码工作,但这似乎是多余的。

#include <string>
#include <map>

struct Element
{    
    double a;
    double b;
};

int main(int argc, char** argv)
{
    Element e {2.0, 3.0};

    std::map<std::string, Element> my_map;
    my_map.try_emplace("hello", 2.0, 3.0);

    return 0;
}

【问题讨论】:

  • 编译器不会生成带参数的 c'tor,try_emplace 只会尝试调用 c'tor(没有聚合初始化)。
  • 但是Element e{2.0, 3.0} 的定义从何而来?
  • @Madden Element 是一个聚合(实际上是一个 POD),即使没有任何构造函数,也支持大括号初始化。我认为这是标准中的一个缺陷,它应该在 emplace_back 中有一个用于聚合的特殊代码。这会更加一致,也不那么令人惊讶。
  • 由于未知原因,STL 对聚合的支持很差!

标签: c++ stl perfect-forwarding emplace


【解决方案1】:

这是因为emplace 方法试图用括号实例化元素,而不是通过聚合初始化。你可以验证一下

Element e(2.0, 3.0);

编译失败,因为没有这样的构造函数(Element e{2.0, 3.0} 绕过了这样的构造函数调用)。但这就是emplace 试图做的事情。要解决此问题,您可以添加适当的构造函数:

struct Element
{
    Element(double a, double b) : a(a), b(b) {}

    double a;
    double b;
};

【讨论】:

    【解决方案2】:

    或者,您可以选择不在 Element 中定义任何用户定义的 ctor,而是使用无论如何仍定义的那些(除非明确删除):

        my_map.try_emplace("hello", Element{2.0, 3.0});
    

    【讨论】:

    • 此方法是否需要一个 Element 对象的副本?
    • @Madden - 是的。但是由于这种类型是一个简单的、可复制的聚合,它可能不会比转发两个双打更糟糕。不要过早优化。
    • 当然,但这只是一个简单的例子——在实践中,我打算做很多放置和更复杂/更大的对象。我将定义特定的构造函数以确保避免复制
    • @Madden 这样的模板化函数通常会转发它们的参数,所以如果你有适当的重载接受右值引用,就应该调用它们。
    猜你喜欢
    • 2011-06-18
    • 2020-05-14
    • 1970-01-01
    • 2012-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    相关资源
    最近更新 更多