Je veux utiliser un tuple consistant en int
, char
, char
dans mon unordered_map
. Je fais comme ça:
#include <string>
#include <unordered_map>
#include <cstring>
#include <iostream>
#include <Tuple>
using namespace std;
Tuple <int,char,char> kk;
unordered_map<kk,int> map;
int main()
{
map[1,"c","b"]=23;
return 0;
}
mais cela me donne les erreurs suivantes:
map.cpp:9:21: error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> class std::unordered_map’
map.cpp:9:21: error: expected a type, got ‘kk’
map.cpp:9:21: error: template argument 3 is invalid
map.cpp:9:21: error: template argument 4 is invalid
map.cpp:9:21: error: template argument 5 is invalid
map.cpp:9:26: error: invalid type in declaration before ‘;’ token
map.cpp: In function ‘int main()’:
map.cpp:14:16: error: assignment of read-only location ‘"b"[map]’
Qu'est-ce que je fais mal en cela?
Les arguments de modèle pour unordered_map ressemblent à ceci:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
std::hash
est non spécialisé pour les n-uplets (faites défiler jusqu'à Spécialisations standard pour les types de bibliothèque). Par conséquent, vous devez fournir le vôtre, quelque chose comme ceci:
typedef std::Tuple<int, char, char> key_t;
struct key_hash : public std::unary_function<key_t, std::size_t>
{
std::size_t operator()(const key_t& k) const
{
return std::get<0>(k) ^ std::get<1>(k) ^ std::get<2>(k);
}
};
// ..snip..
typedef std::unordered_map<const key_t,data,key_hash,key_equal> map_t;
// ^ this is our custom hash
Et enfin, comme Benjamin Lindley répond déjà, vous devez utiliser std::make_Tuple
:
// d is data
m[std::make_Tuple(1, 'a', 'b')] = d;
auto itr = m.find(std::make_Tuple(1, 'a', 'b'));
Le code a été récupéré à partir de en utilisant un std :: Tuple comme clé pour std :: unordered_map et voici le Exemple en direct .
Première erreur:
map.cpp:9:21: error: expected a type, got ‘kk’
Comme le dit clairement l’erreur, le paramètre template doit être un type. kk
n'est pas un type, c'est un objet. Peut-être que vous vouliez en faire un typedef?
typedef Tuple <int,char,char> kk;
unordered_map<kk,int> map;
Deuxième erreur:
map[1,"c","b"]=23;
Deux problèmes ici. Premièrement, mettre des virgules entre les valeurs n'en fait pas un tuple. Vous devez être explicite à ce sujet, en appelant le constructeur de votre type Tuple ou en utilisant une fonction qui retourne un Tuple (par exemple, std::make_Tuple
). Deuxièmement, votre tuple attend des caractères ('c','b'
) et non des chaînes ("c","b"
).
map[std::make_Tuple(1,'c','b')] = 23;
Comme indiqué, std :: hash n'est pas spécialisé pour les n-uplets. Toutefois, si votre tuple est constitué de types standard pouvant être hachés, tels que string et int, le code suivant provenant de generic-hash-to-tuples-in-unordered-map-unordered-set ajoutera automatiquement cette prise en charge dans c ++ 11 .
Il suffit de coller le code dans un fichier d'en-tête et de l'inclure à tout moment:
#include <Tuple>
// function has to live in the std namespace
// so that it is picked up by argument-dependent name lookup (ADL).
namespace std{
namespace
{
// Code from boost
// Reciprocal of the golden ratio helps spread entropy
// and handles duplicates.
// See Mike Seymour in magic-numbers-in-boosthash-combine:
// https://stackoverflow.com/questions/4948780
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
seed ^= hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
// Recursive template code derived from Matthieu M.
template <class Tuple, size_t Index = std::Tuple_size<Tuple>::value - 1>
struct HashValueImpl
{
static void apply(size_t& seed, Tuple const& Tuple)
{
HashValueImpl<Tuple, Index-1>::apply(seed, Tuple);
hash_combine(seed, get<Index>(Tuple));
}
};
template <class Tuple>
struct HashValueImpl<Tuple,0>
{
static void apply(size_t& seed, Tuple const& Tuple)
{
hash_combine(seed, get<0>(Tuple));
}
};
}
template <typename ... TT>
struct hash<std::Tuple<TT...>>
{
size_t
operator()(std::Tuple<TT...> const& tt) const
{
size_t seed = 0;
HashValueImpl<std::Tuple<TT...> >::apply(seed, tt);
return seed;
}
};
}
J'avais besoin d'une carte au lieu d'une carte non ordonnée:
la clé était 3-Tuple et
valeur était un 4-Tuple
voyant toutes les réponses, j'étais sur le point de passer aux paires
mais ci-dessous a fonctionné pour moi:
// declare a map called map1
map <
Tuple<short, short, short>,
Tuple<short, short, short, short>
> map1;
// insert an element into map1
map1[make_Tuple(1, 1, 1)] = make_Tuple(0, 0, 1, 1);
// this also worked
map1[{1, 1, 1}] = { 0, 0, 1, 1 };
J'utilise visual studio community 2015 ide
Voici une méthode pour utiliser Tuple en tant que clé d'un unordered_map sans utiliser de spécialisation de hachage:
#include <string>
#include <Tuple>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <unordered_map>
using namespace std;
string fToStr(unordered_map<double,int>& dToI,float x)
{
static int keyVal=0;
stringstream ss;
auto iter = dToI.find(x);
if(iter == dToI.end()) {
dToI[x]=++keyVal;
ss << keyVal;
} else {
ss << iter->second;
}
return ss.str();
}
typedef Tuple<int,char,char> TICC;
const char ReservedChar=',';
string getKey(TICC& t)
{
stringstream ss;
ss << get<0>(t) << ReservedChar << get<1>(t) << ReservedChar << get<2>(t);
return ss.str();
}
int main()
{
unordered_map< string,TICC > tupleMp;
vector<TICC> ticc={make_Tuple(1, 'a', 'b'),make_Tuple(1, 'b', 'c'),make_Tuple(2, 'a', 'b')};
for(auto t : ticc)
tupleMp[getKey(t)]=t;
for(auto t : ticc) {
string key = getKey(t);
auto val = tupleMp[key];
cout << "tupleMp[" << key << "]={" << get<0>(val) << "," << get<1>(val) << ","<< get<2>(val) << "} ";
}
cout << endl;
//for float Tuple elements use a second float to int key map
unordered_map< double,int > dToI;
vector<float> v{1.234,1.234001,1.234001};
cout << "\nfloat keys: ";
for(float f : v)
cout << setprecision(7) << f << "=" << fToStr(dToI,f) << " ";
cout << endl;
return 0;
}
La sortie est:
tupleMp[1,a,b]={1,a,b} tupleMp[1,b,c]={1,b,c} tupleMp[2,a,b]={2,a,b}
float keys: 1.234=1 1.234001=2 1.234001=2