C++ 在无序映射中使用元组

C++ 在无序映射中使用元组,c++,hashmap,unordered-map,stdtuple,C++,Hashmap,Unordered Map,Stdtuple,我想在我的无序映射中使用由int、char、char组成的元组。我是这样做的: #include <string> #include <unordered_map> #include <cstring> #include <iostream> #include <tuple> using namespace std; tuple <int,char,char> kk; unordered_map<kk,int>

我想在我的
无序映射
中使用由
int
char
char
组成的元组。我是这样做的:

#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;
}
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;
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
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
元组kk;
无序地图;
int main()
{
map[1,“c”,“b”]=23;
返回0;
}
但这给了我以下错误:

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]’
map.cpp:9:21:错误:“模板类std::无序映射”的模板参数列表中参数1的类型/值不匹配
map.cpp:9:21:错误:应为类型,但得到“kk”
map.cpp:9:21:错误:模板参数3无效
map.cpp:9:21:错误:模板参数4无效
map.cpp:9:21:错误:模板参数5无效
map.cpp:9:26:错误:在“;”之前的声明中的类型无效代币
map.cpp:在函数“int main()”中:
map.cpp:14:16:错误:分配只读位置“b”[map]”
我在这方面做错了什么?

第一个错误:

map.cpp:9:21: error:   expected a type, got ‘kk’
正如错误明确指出的,模板参数需要是一个类型
kk
不是类型,而是对象。也许你想把它做成一个typedef

typedef tuple <int,char,char> kk;
unordered_map<kk,int> map;
这里有两个问题。首先,在值之间加逗号并不能构成元组。您需要明确说明这一点,要么调用元组类型的构造函数,要么使用返回元组的函数(例如
std::make_tuple
)。其次,元组需要的是字符(
'c','b'
),而不是字符串(
'c','b'


无序_映射的模板参数如下所示:

#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;
}
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;
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
最后,由于Benjamin Lindley的答案已经给出了地址,您需要使用
std::make\u tuple

// d is data
m[std::make_tuple(1, 'a', 'b')] = d;
auto itr = m.find(std::make_tuple(1, 'a', 'b'));

代码是从中获取的,这里是。

正如所指出的,std::hash不是元组专用的。但是,如果元组由标准的可散列类型(如string和int)组成,那么下面的代码将自动在c++11中添加此类支持

只需将代码粘贴到头文件中,并在需要时将其包括在内:

#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;                                 
        }                                              

    };
}
#包括
//函数必须位于std命名空间中
//因此,它由参数相关名称查找(ADL)获取。
名称空间标准{
名称空间
{
//来自boost的代码
//黄金比率的倒数有助于传播熵
//并处理重复项。
//参见迈克·西摩在boosthash combine中的神奇数字:
//     https://stackoverflow.com/questions/4948780
模板
内联无效哈希组合(标准::大小\u t和种子,t常量和v)
{
seed^=hash()(v)+0x9e3779b9+(seed2);
}
//从Matthieu M派生的递归模板代码。
模板
结构HashValueImpl
{
静态无效应用(大小和种子、元组常量和元组)
{
HashValueImpl::apply(种子,元组);
hash_combine(seed,get(tuple));
}
};
模板
结构HashValueImpl
{
静态无效应用(大小和种子、元组常量和元组)
{
hash_combine(seed,get(tuple));
}
};
}
模板
结构散列
{
尺寸
运算符()(std::tuple const&tt)const
{                                              
种子大小=0;
HashValueImpl::apply(seed,tt);
返回种子;
}                                              
};
}

我需要的是地图而不是无序的地图:
关键是三元组和
值是一个4元组

看到所有的答案,我正要换成双人

但是,以下内容对我很有用:

// 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 };
//声明一个名为map1的映射
地图<
元组,
元组
>map1;
//在map1中插入一个元素
map1[make_tuple(1,1,1)]=make_tuple(0,0,1,1);
//这也起了作用
map1[{1,1,1}]={0,0,1,1};

我使用的是visual studio community 2015 ide

这里有一种方法,可以在不使用哈希专门化的情况下,将元组用作无序_映射的键:

#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;
}
读了一篇文章后,我最终得出了这个结论。它使用了一种高效的散列组合算法,并且没有专门化
std
名称空间中的内容。如果希望此代码通常适用于任何可哈希元素的元组,则需要做更多的工作

这适用于C++11及更高版本。在C++03中,可以使用
boost::hash
代替
std::hash

typedef元组MyTuple;
//为此元组定义哈希函数
struct KeyHash:public std::一元函数{
std::size\u t运算符()(常量MyTuple&k)常量{
//下面的神奇操作使得碰撞的可能性比标准的XOR要小
std::size_t seed=std::hash()(std::get(k));
seed^=std::hash()(std::get(k))+0x9e3779b9+(seed>2);
返回seed^(std::hash()(std::get(k))+0x9e3779b9+(seed>2));
}
};
//定义此元组的比较运算符
结构KeyEqual:public std::binary_函数{
布尔运算符()(常量MyTuple&v0,常量MyTuple&v1)常量{
返回(std::get(v0)==std::get(v1)和&std::get(v0)==std::get(v1)&&
std::get(v0)=std::get(v1));
}
};
typedef无序映射MyMap;

对于那些使用
boost
的人,他们可以使用此选项将哈希重新路由到boost的实现中

#include "boost/functional/hash.hpp"
#include <string>
#include <unordered_map>
#include <cstring>
#include <iostream>
#include <tuple>


using Key = std::tuple<int, char, char>;

struct KeyHash {
    std::size_t operator()(const Key & key) const
    {
        return boost::hash_value(key);
    }
};

using Map = std::unordered_map<Key, int, KeyHash>;

int main()
{
    Map map;
    map[1,"c","b"] = 23;
    return 0;
}
#包括“boost/functional/hash.hpp”
#包括
#包括
#包括
#包括
#包括
使用Key=std::tuple;
结构键哈希{
std::size\u t运算符()(常数键和键)常数
{
返回boost::hash_值(key);
}
};
使用Map=std::无序_映射;
int main()
{
地图;
map[1,“c”,“b”]=23;
返回0;
}

您能解释一下您是如何定义密钥散列的吗?或者在key_hash中做了什么?@Zara查看链接了解更多信息<上面定义了代码>密钥散列。稍后,我们将其用作模板参数之一(无序_映射需要散列)