如何在地图中使用自定义类的位置?



这是我的自定义类,我将其用作键。接下来是值,我用它作为向量。当我试图使用统一初始化时,我得到了编译错误。我无法理解这个错误到底是什么意思?下面是错误和代码。

基于某人对插入的建议-如何使用insert_or_assign在映射自定义类?

我对emplace()使用了类似的东西。然而,它不工作。

炮位原型显示-

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

表示参数&&只是类Args的右值引用,对吗?

在我的例子中,实参就是std::vector。我如何安置?

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

我不经常需要它,但有时我需要它:a "real"std::map中的emplace()。大多数情况下,它会给我带来一些麻烦,直到我把它弄好,但大多数情况下,我终于明白了。

我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. 我提供了一个move构造函数。所以,前两个安置版本(抄袭宋元尧的回答)使用了这个。(如果没有移动构造函数,emplace()将使用MyData的复制构造函数来代替-正如op所指出的。)

  2. 我使用了我最后的手段piecewise_construct(它已经在c++ 11中工作得很好)。这个实际上是"真实的"emplace(即就地施工).

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

表示参数&&只是类Args的右值引用,对吗?在我的例子中,参数就是std::vector。我如何安置?

注意,键和值都传递给emplace来构造map中的元素。(顺便说一句,Args&&不是右值引用,而是转发引用)

问题是像{32, "SJ"s}这样的带括号的init-list没有类型,这导致在调用emplace时模板参数推导失败。

Non-deduced上下文:

  • 参数P,其Aa braced-init-list, but P is not std::initializer_list, a reference to one (possibly cv-qualified), or (since C++17)是对数组的引用吗?
  • 您可以显式地传递MyData:

    studentClasses.emplace(MyData{32, "SJ"s}, std::vector{"working"s});
    

    或指定模板参数为:

    studentClasses.emplace<MyData>({32, "SJ"s}, std::vector{"working"s});
    

    最新更新