Использование пары в качестве ключа на карте (C++/STL)

Я хочу использовать пару из STL в качестве ключа карты.

#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++.

Как я могу использовать пару в качестве ключа на карте? И вообще Как я могу использовать любую структуру (объекты, структуры и т.д.) в качестве ключа на карте?

Спасибо!


person ccarpenterg    schedule 18.07.2010    source источник
comment
В будущем, пожалуйста, публикуйте сообщения об ошибках, которые вы получаете. В противном случае людям часто бывает трудно или невозможно помочь вам. :)   -  person James McNellis    schedule 19.07.2010
comment
Если вы опубликуете ошибки, я уверен, что мы также могли бы помочь объяснить, что они означают и как вы можете интерпретировать их, когда увидите их в будущем.   -  person James McNellis    schedule 19.07.2010
comment
Обратите внимание, что при использовании строковых литералов сравниваются адреса строк, а не сами строки. Вам лучше использовать std::string.   -  person sbi    schedule 19.07.2010
comment
Также взгляните на Почему я не могу скомпилировать unordered_map с парой в качестве ключа?   -  person y2k-shubham    schedule 03.09.2020


Ответы (6)


std::map::insert принимает один аргумент: пару ключ-значение, поэтому вам нужно будет использовать:

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

Вы должны использовать std::string вместо строк C в своих типах. Как и сейчас, вы, скорее всего, не получите ожидаемых результатов, потому что поиск значений на карте будет выполняться путем сравнения указателей, а не путем сравнения строк.

Если вы действительно хотите использовать строки C (чего, опять же, делать не следует), то вам нужно использовать const char* вместо char* в своих типах.

И вообще Как я могу использовать любую структуру (объекты, структуры и т.д.) в качестве ключа на карте?

Вам нужно перегрузить operator< для типа ключа или использовать собственный компаратор.

person James McNellis    schedule 18.07.2010
comment
mapa[p1] = "Manzana"; еще короче - person Peter G.; 19.07.2010
comment
@Peter: operator[] имеет другую семантику, и я бы рекомендовал не использовать его для вставки объектов в map (он вставляет новый объект, если он еще не существует, а затем немедленно перезаписывает вновь созданный временный объект). - person James McNellis; 19.07.2010
comment
Вау, это была ужасная ошибка, я забыл сделать пару. Мне жаль! Сейчас это работает, но не работало, когда я использовал char* вместо const char*. Что делать с const char* против char* в этом случае? Спасибо! - person ccarpenterg; 19.07.2010
comment
@ccarpenterg: Не нужно извиняться передо мной. :-) Строковые литералы имеют тип const char[], парный тип имеет член типа char*; конструктор пары не может удалить квалификатор const. Это сказало; на самом деле: используйте std::string, использование указателя в качестве ключа карты почти всегда является плохой идеей. - person James McNellis; 19.07.2010
comment
@JamesMcNellis, можете ли вы обновить это до современного C++? Я удивлялся, что мой std::map работал без проблем с std::pair, пока не заметил, что поскольку C ++14 он operator< определен. - person andreee; 24.05.2019

Вот рабочая переработка рассматриваемого кода:

#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;
}
person Alec Jacobson    schedule 11.01.2011
comment
Зачем? чем это лучше, чем то, что было у OP с pair? - person user102008; 15.10.2011
comment
Гм, потому что он компилируется и выполняется правильно? - person Alec Jacobson; 15.11.2012
comment
operator < может быть не так точен, как std::pairs. - person Jichao; 12.09.2015
comment
@Jichao этот ответ был написан до C++14. operator < for std::pair существует только с C++14. - person andreee; 24.05.2019

В качестве альтернативы тому, что заявил Джеймс Макнеллис:

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

вы могли бы использовать mapa.insert({p1, "Manzana"});

person Julian Declercq    schedule 09.12.2015
comment
@ccarpenterg: Это должен быть предпочтительный и принятый ответ от С++ 14! - person andreee; 24.05.2019

Это аналогичная версия того, что вы хотите сделать, просто измените типы данных, вот и все. Кроме того, используйте строку 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));
}   
person Kumar Utkarsh    schedule 08.04.2019

std::map::emplace — ваш друг.

mapa.emplace(p1, "Manzana");
person Shishir Jaiswal    schedule 11.05.2021

Это будет делать именно то, что вы хотите

#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;
}
person trahul    schedule 10.03.2018
comment
Я хотел бы услышать ваши предложения. - person trahul; 01.03.2019
comment
Смотрите ответ Джулиана. Ваш код не ремонтопригоден. Прекрасный пример того, что проще переписать, чем исправить. - person Sergei; 01.03.2019