如何在地图中使用 emplace 进行自定义类?

ank*_*yar 3 c++ templates stdmap c++11

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

\n

根据某人关于插入的建议 - How to use insert_or_assign in map for custom class?

\n

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

\n

emplace 的原型是这样的——

\n
https://en.cppreference.com/w/cpp/container/map/emplace\ntemplate< class... Args >\nstd::pair<iterator,bool> emplace( Args&&... args );\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

就我而言,arg 只是 std::vector。\n我该如何进行 emplace?

\n
class MyData\n{\n    private:\n        int age;\n      string name;\n   public:\n      int getAge() const\n      {\n         return age;\n      }\n      string& getName()\n      {\n        return name; \n      }\n      MyData(int age_val, string name_val): age(age_val), name(name_val) \n      {\n         cout<<"Constructor invoked"<<endl;\n      }\n      bool operator <(const MyData &other) const\n      {\n         return age < other.age;\n      }\n      MyData(const MyData& other)\n      {\n         cout<<"Copy constructor invoked"<<endl;\n         age = other.age;\n         name = other.name;\n      }\n};\n\nint main(int argc, char **argv)\n{\n   std::map<MyData, vector<string>> studentClasses;\n   studentClasses.emplace({32, "SJ"s}, std::vector{"working"s});\n   \n    return 0;\n}\n\n\n\nIn function \xe2\x80\x98int main(int, char**)\xe2\x80\x99:\nmap.cpp:62:63: error: no matching function for call to \xe2\x80\x98std::map<MyData, std::vector<std::__cxx11::basic_string<char> > >::emplace(<brace-enclosed initializer list>, std::vector<std::__cxx11::basic_string<char> >)\xe2\x80\x99\n   62 |    studentClasses.emplace({32, "SJ"s}, std::vector{"working"s});\n   \n   574 |  emplace(_Args&&... __args)\n      |  ^~~~~~~\n/usr/include/c++/9/bits/stl_map.h:574:2: note:   candidate expects 0 arguments, 2 provided\n
Run Code Online (Sandbox Code Playgroud)\n

Sch*_*eff 5

我不经常需要它,但有时我需要它:一个“真正的emplace()std::map. Most times it causes me some trouble until I get it working but most times I finally got.

\n

我的MCVE:

\n
#include <iostream>\n#include <map>\n#include <string>\n#include <vector>\n\nusing namespace std::string_literals;\n\nstruct MyData {\n  int age;\n  std::string name;\n  \n  MyData(int age, std::string name): age(age), name(name)\n  {\n    std::cout << "MyData::MyData(int, std::string)\\n";\n  }\n  \n  MyData(const MyData& myData): age(myData.age), name(myData.name)\n  {\n    std::cout << "MyData::MyData(const MyData&)\\n";\n  }\n  \n  MyData(MyData&& myData) noexcept:\n    age(std::move(myData.age)), name(std::move(myData.name))\n  {\n    std::cout << "MyData::MyData(MyData&&)\\n";\n  }\n\n  bool operator<(const MyData& myData) const\n  {\n    return age < myData.age\n      || (age == myData.age && name < myData.name);\n  }\n};\n\n#define DEBUG(...) std::cout << "Exec: " #__VA_ARGS__ << ";\\n"; __VA_ARGS__ \n\nint main()\n{\n  DEBUG(std::map<MyData, std::vector<std::string>> studentClasses);\n  DEBUG(studentClasses.emplace(MyData{32, "SJ"s}, std::vector{"working"s}));\n  DEBUG(studentClasses.emplace<MyData>({32, "SJ"s}, std::vector{"working"s}));\n  DEBUG(studentClasses.emplace(std::piecewise_construct,\n    std::forward_as_tuple(32, "SJ"s),\n    std::forward_as_tuple(std::vector{ "working"s })));\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
#include <iostream>\n#include <map>\n#include <string>\n#include <vector>\n\nusing namespace std::string_literals;\n\nstruct MyData {\n  int age;\n  std::string name;\n  \n  MyData(int age, std::string name): age(age), name(name)\n  {\n    std::cout << "MyData::MyData(int, std::string)\\n";\n  }\n  \n  MyData(const MyData& myData): age(myData.age), name(myData.name)\n  {\n    std::cout << "MyData::MyData(const MyData&)\\n";\n  }\n  \n  MyData(MyData&& myData) noexcept:\n    age(std::move(myData.age)), name(std::move(myData.name))\n  {\n    std::cout << "MyData::MyData(MyData&&)\\n";\n  }\n\n  bool operator<(const MyData& myData) const\n  {\n    return age < myData.age\n      || (age == myData.age && name < myData.name);\n  }\n};\n\n#define DEBUG(...) std::cout << "Exec: " #__VA_ARGS__ << ";\\n"; __VA_ARGS__ \n\nint main()\n{\n  DEBUG(std::map<MyData, std::vector<std::string>> studentClasses);\n  DEBUG(studentClasses.emplace(MyData{32, "SJ"s}, std::vector{"working"s}));\n  DEBUG(studentClasses.emplace<MyData>({32, "SJ"s}, std::vector{"working"s}));\n  DEBUG(studentClasses.emplace(std::piecewise_construct,\n    std::forward_as_tuple(32, "SJ"s),\n    std::forward_as_tuple(std::vector{ "working"s })));\n}\n
Run Code Online (Sandbox Code Playgroud)\n

coliru 演示

\n
    \n
  1. 我提供了一个移动构造函数。因此,前两个 emplace 版本(从Songyuanyao 的回答复制)使用了那个版本。(如果没有移动构造函数,emplace()将使用复制构造函数MyData instead \xe2\x80\x93 as pointed out by the OP.)

    \n
  2. \n
  3. 我使用了最后的手段piecewise_construct(它已经在 C++11 中工作得很好)。\n这实际上是“真正的”emplace (i.e. in-place construction).

    \n
  4. \n
\n

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

\n