如何在地图中使用 emplace 进行自定义类? [英] How to use emplace in map for custom class?

查看:31
本文介绍了如何在地图中使用 emplace 进行自定义类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的自定义类,我将其用作密钥.接下来是值,我将其用作向量.当我尝试使用统一初始化时,出现编译错误.我无法理解该错误的真正含义?这是错误和代码.

Here is my custom class, which I am using as a key. Next is the value, which I am using as vector. While I am trying to use uniform initialization, I get the compilation error. I am unable to understand what that error really means? Here is the error and the code.

基于某人关于插入的建议 - 如何在自定义类的地图中使用 insert_or_assign ?

Based on the advise by somebody on insert - How to use insert_or_assign in map for custom class?

我对 emplace() 使用了类似的东西.但是,它不起作用.

I am using the similar thing for emplace(). However, it is not working.

emplace的原型说-

The prototype of emplace says -

https://en.cppreference.com/w/cpp/container/map/emplace
template< class... Args >
std::pair<iterator,bool> emplace( Args&&... args );

这意味着 Args &&只是类 Args 的右值引用对吗?

It means the Args && is nothing but rvalue reference of class Args right?

就我而言,arg 只不过是 std::vector.我该怎么做?

In my case, the arg is nothing but std::vector. How can I do emplace?

class MyData
{
    private:
        int age;
      string name;
   public:
      int getAge() const
      {
         return age;
      }
      string& getName()
      {
        return name; 
      }
      MyData(int age_val, string name_val): age(age_val), name(name_val) 
      {
         cout<<"Constructor invoked"<<endl;
      }
      bool operator <(const MyData &other) const
      {
         return age < other.age;
      }
      MyData(const MyData& other)
      {
         cout<<"Copy constructor invoked"<<endl;
         age = other.age;
         name = other.name;
      }
};

int main(int argc, char **argv)
{
   std::map<MyData, vector<string>> studentClasses;
   studentClasses.emplace({32, "SJ"s}, std::vector{"working"s});
   
    return 0;
}



In function ‘int main(int, char**)’:
map.cpp:62:63: error: no matching function for call to ‘std::map<MyData, std::vector<std::__cxx11::basic_string<char> > >::emplace(<brace-enclosed initializer list>, std::vector<std::__cxx11::basic_string<char> >)’
   62 |    studentClasses.emplace({32, "SJ"s}, std::vector{"working"s});
   
   574 |  emplace(_Args&&... __args)
      |  ^~~~~~~
/usr/include/c++/9/bits/stl_map.h:574:2: note:   candidate expects 0 arguments, 2 provided

推荐答案

我并不经常需要它,但有时我需要它:一个真实"的emplace()std::map 中.大多数时候它会给我带来一些麻烦,直到我开始工作,但大多数时候我终于得到了.

I don't need it often but sometimes I need it: a "real" emplace() in a std::map. Most times it causes me some trouble until I get it working but most times I finally got.

我的 MCVE:

#include <iostream>
#include <map>
#include <string>
#include <vector>

using namespace std::string_literals;

struct MyData {
  int age;
  std::string name;
  
  MyData(int age, std::string name): age(age), name(name)
  {
    std::cout << "MyData::MyData(int, std::string)\n";
  }
  
  MyData(const MyData& myData): age(myData.age), name(myData.name)
  {
    std::cout << "MyData::MyData(const MyData&)\n";
  }
  
  MyData(MyData&& myData) noexcept:
    age(std::move(myData.age)), name(std::move(myData.name))
  {
    std::cout << "MyData::MyData(MyData&&)\n";
  }

  bool operator<(const MyData& myData) const
  {
    return age < myData.age
      || (age == myData.age && name < myData.name);
  }
};

#define DEBUG(...) std::cout << "Exec: " #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{
  DEBUG(std::map<MyData, std::vector<std::string>> studentClasses);
  DEBUG(studentClasses.emplace(MyData{32, "SJ"s}, std::vector{"working"s}));
  DEBUG(studentClasses.emplace<MyData>({32, "SJ"s}, std::vector{"working"s}));
  DEBUG(studentClasses.emplace(std::piecewise_construct,
    std::forward_as_tuple(32, "SJ"s),
    std::forward_as_tuple(std::vector{ "working"s })));
}

输出:

Exec: std::map<MyData, std::vector<std::string>> studentClasses;
Exec: studentClasses.emplace(MyData{32, "SJ"s}, std::vector{"working"s});
MyData::MyData(int, std::string)
MyData::MyData(MyData&&)
Exec: studentClasses.emplace<MyData>({32, "SJ"s}, std::vector{"working"s});
MyData::MyData(int, std::string)
MyData::MyData(MyData&&)
Exec: studentClasses.emplace(std::piecewise_construct, std::forward_as_tuple(32, "SJ"s), std::forward_as_tuple(std::vector{ "working"s }));
MyData::MyData(int, std::string)

coliru 演示

  1. 我提供了一个移动构造函数.所以,前两个 emplace 版本(从 songyuanyao's answer 复制)使用那个.(在没有移动构造函数的情况下,emplace() 将使用 MyData 的复制构造函数 - 正如 OP 所指出的那样.)

  1. I provided a move constructor. So, the first two emplace versions (copied from songyuanyao's answer) use that one. (Without a move constructor, emplace() would use the copy constructor of MyData instead – as pointed out by the OP.)

我使用了我最后的手段 piecewise_construct(它在 C++11 中已经很好用了).这实际上是真实的"emplace(即就地构建).

I used my last resort piecewise_construct (which already worked as well in C++11). This one does in fact the "real" emplace (i.e. in-place construction).

进一步阅读:cppreference.com: std::map::emplace()

这篇关于如何在地图中使用 emplace 进行自定义类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆