在C++/STL中,如何使用pair作为map的键?

44

我想使用STL中的一对作为map的键。

#include <iostream>
#include <map>

using namespace std;

int main() {

typedef pair<char*, int> Key;
typedef map< Key , char*> Mapa;

Key p1 ("Apple", 45);
Key p2 ("Berry", 20);

Mapa mapa;

mapa.insert(p1, "Manzana");
mapa.insert(p2, "Arandano");

return 0;

}

但编译器抛出了一堆难以理解的信息,而我对C和C++非常陌生。

我该如何在map中使用pair作为键?并且通用的说,我该如何使用任何类型的结构(对象,结构体等)作为map的键?

谢谢!


7
将来请发布您收到的错误信息。否则,人们往往会难以或无法帮助您解决问题。 :) - James McNellis
3
如果您发布错误信息,我们可以帮助解释它们的含义以及在将来遇到时如何进行解读。 - James McNellis
1
请注意,使用字符串字面量比较的是字符串的地址,而不是字符串本身。最好使用std::string - sbi
还可以看一下这个问题:为什么我不能使用pair作为unordered_map的键进行编译? - y2k-shubham
6个回答

35

std::map::insert只接受一个参数:键值对,因此您需要使用:

mapa.insert(std::make_pair(p1, "Manzana"));

在您的类型中,应该使用std::string而不是C字符串。目前情况下,查找映射值将通过比较指针而不是比较字符串来完成,因此您可能无法得到期望的结果。

如果您真的想使用C字符串(再次强调,您不应该这样做),则需要在您的类型中使用const char*而不是char*

总的来说,我如何在Map中使用任何类型的结构(对象、结构体等)作为键?

您需要重载键类型的operator<或使用自定义比较器。


2
mapa[p1] = "Manzana"; 更短。 - Peter G.
4
@Peter: operator[] 的语义不同,我建议不要用它来将对象插入到 map 中(如果一个对象不存在,则会插入一个新的对象,然后立即覆盖新创建的临时对象)。 - James McNellis
哇,那是一个丑陋的错误,我忘记了制作一对。非常抱歉! 现在它可以工作了,但当我使用char而不是const char时它无法工作。在这种情况下,const char与char有什么区别?谢谢! - ccarpenterg
1
@ccarpenterg:不需要向我道歉。字符串字面量具有类型const char [],对类型为char *的成员进行了配对;对于构造函数而言,无法移除const限定符。话虽如此,真的:请使用std::string,将指针用作映射键几乎总是一个坏主意。 - James McNellis
@JamesMcNellis,能否将此更新为现代C++?我曾想知道为什么我的std::map在使用std::pair时没有问题,直到我注意到自C++14起已定义了operator< - andreee

8

以下是问题代码的有效重写:

#include <map>
#include <string>

class Key
{
  public: 
    Key(std::string s, int i)
    {
      this->s = s;
      this->i = i;
    }
    std::string s;
    int i;
    bool operator<(const Key& k) const
    {
      int s_cmp = this->s.compare(k.s);
      if(s_cmp == 0)
      {
        return this->i < k.i;
      }
      return s_cmp < 0;
    }
};

int main()
{


  Key p1 ("Apple", 45);
  Key p2 ("Berry", 20);

  std::map<Key,std::string> mapa;

  mapa[p1] = "Manzana";
  mapa[p2] = "Arandano";

  printf("mapa[%s,%d] --> %s\n",
    p1.s.c_str(),p1.i,mapa.begin()->second.c_str());
  printf("mapa[%s,%d] --> %s\n",
    p2.s.c_str(),p2.i,(++mapa.begin())->second.c_str());

  return 0;
}

2
为什么?这样做有什么比 OP 使用 pair 更好的地方吗? - user102008
7
因为它能正确编译和执行? - Alec Jacobson
"operator <" 可能不像 std::pair 的那么精确。 - Jichao
2
@Jichao 这个答案是在 C++14 之前编写的。std::pairoperator < 只存在于 C++14 - andreee

5
与詹姆斯·麦克内利斯所说的相反,您可以选择以下方法:
mapa.insert(std::make_pair(p1, "Manzana"));

您可以使用 mapa.insert({p1, "Manzana"});


1
@ccarpenterg:那应该是C++14的首选和被接受的答案! - andreee

1
这是一个类似于你想要做的版本,只需更改数据类型即可。此外,使用C++字符串,而不是我们在C中使用的那种。
#include<bits/stdc++.h>
using namespace std;
#define  ll long long int
typedef pair<ll,ll> my_key_type;
typedef map<my_key_type,ll> my_map_type;
int  main()
{
    my_map_type m;
    m.insert(make_pair(my_key_type(30,40),6));
}   

0

-1

这将完全按照您的要求执行

#include<bits/stdc++.h>
using namespace std;
int main()
{
    map<pair<string, long long int>, string> MAP;
    pair<string, long long int> P;
    MAP.insert(pair<pair<string, long long int>, string>(pair<string, long long int>("Apple", 45), "Manzana"));
    MAP.insert(pair<pair<string, long long int>, string>(pair<string, long long int>("Berry", 20), "Arandano"));
    P = make_pair("Berry", 20);
    //to find berry, 20
    cout<<MAP[P]<<"\n";
    return 0;
}

我想听听你的建议。 - trahul
看看朱利安的回答。你的代码是不可维护的。这是“重写比修复更容易”的完美例子。 - Sergei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接