C++ 如何使映射键具有两种不同的数据类型?

C++ 如何使映射键具有两种不同的数据类型?,c++,stdtuple,std-variant,C++,Stdtuple,Std Variant,我有一个std::unordered_map容器,其中Key可以是两种数据类型: 64位无符号整数 具有(8位无符号整数、8位无符号整数、16位无符号整数、32位无符号整数)的元组 但是value是一种对象类型,它与这两种键类型相同 我尝试过的一件事是将键设为std::variant,这样它就可以同时保存这两种类型。根据某些条件检查,将密钥设置为以下类型之一: void A::a() { std::varaint<type1, type2> Id; //key

我有一个
std::unordered_map
容器,其中
Key
可以是两种数据类型:

  • 64位无符号整数
  • 具有(8位无符号整数、8位无符号整数、16位无符号整数、32位无符号整数)的元组
但是value是一种对象类型,它与这两种键类型相同

我尝试过的一件事是将键设为
std::variant
,这样它就可以同时保存这两种类型。根据某些条件检查,将密钥设置为以下类型之一:

void A::a() {
    std::varaint<type1, type2> Id; //key

    if (condition) {
        Id = 64 bit unsigned value;
    }
    else {
        Id = tuple<.....>;
    }
}

unorderedmap[Id] = obj1;
// ^-- gives compile-time error
// (expecting Id specialized to either of the variant types)

有没有办法修复std::variant,或者我应该使用另一种方法?

这似乎很好:

#include <iostream>
#include <unordered_map>
#include <string>
#include <variant>

typedef std::variant<int, std::string> mytype;

std::unordered_map<mytype, int> m;

int main()
{
    m[5] = 20;
    std::cout << m[5];
    m["hey"] = 10;
    std::cout << m["hey"];
    mytype tmp = "hey";
    std::cout << m[tmp];
}

您可以将
名称空间std{}
部分的所有内容都放在头的内部,然后只在需要的地方包含该头(我省略了include-guards,所以ofc会像往常一样添加它)。如果标准赶上并实现了元组哈希,只需删除头文件。

这似乎很好:

#include <iostream>
#include <unordered_map>
#include <string>
#include <variant>

typedef std::variant<int, std::string> mytype;

std::unordered_map<mytype, int> m;

int main()
{
    m[5] = 20;
    std::cout << m[5];
    m["hey"] = 10;
    std::cout << m["hey"];
    mytype tmp = "hey";
    std::cout << m[tmp];
}

您可以将
名称空间std{}
部分的所有内容都放在头的内部,然后只在需要的地方包含该头(我省略了include-guards,所以ofc会像往常一样添加它)。如果标准赶上并实现了元组哈希,只需删除头文件。

请提供。为什么不使用
模板
?您的问题是什么?“任何建议”在这里都是离题的。工作代码在这里是离题的。如果您有特定的问题,我们很乐意为您提供帮助,但您需要指定它并创建一个显示您的
无序映射
声明。你使用哪个
Hash
KeyEqual
呢?人们说“完整且可验证”的意思是你不应该发布拼写错误(
std::varaint
)或其他明显错误的代码(使用
Id
超出
A::A()
)。如果你想要真正的帮助,你需要发布真正的代码。您应该能够生成一个小示例,任何人都可以尝试编译并获得您得到的文字准确错误,并编辑您的问题以提供该代码。请提供。为什么不使用
模板
?您的问题是什么?“任何建议”在这里都是离题的。工作代码在这里是离题的。如果您有特定的问题,我们很乐意为您提供帮助,但您需要指定它并创建一个显示您的
无序映射
声明。你使用哪个
Hash
KeyEqual
呢?人们说“完整且可验证”的意思是你不应该发布拼写错误(
std::varaint
)或其他明显错误的代码(使用
Id
超出
A::A()
)。如果你想要真正的帮助,你需要发布真正的代码。您应该能够生成一个小示例,任何人都可以尝试编译并获得您得到的文字上的准确错误,并编辑您的问题以提供代码。当然,有一些方法可以完全封装这个示例并保证安全。@MilesBudnek啊,我误解了。我更新了我的答案。实际的问题是
std::tuple
没有
hash\u映射
专门化,因此具有
std::tuple
作为参数的
std::variant
也没有。因此,用
std::tuple
替换
std::string
,代码将无法编译。@bolov如何对tuple类型进行哈希映射专门化?有吗suggestions@bvb我已经更新了我的答案,看看它是否对你有效。当然有办法完全封装这个,并保证安全。@MilesBudnek啊,我误解了。我更新了我的答案。实际的问题是
std::tuple
没有
hash\u映射
专门化,因此具有
std::tuple
作为参数的
std::variant
也没有。因此,用
std::tuple
替换
std::string
,代码将无法编译。@bolov如何对tuple类型进行哈希映射专门化?有吗suggestions@bvb我已经更新了我的答案,看看它是否适合你。
#include <iostream>
#include <string>
#include <variant>
#include <unordered_map>
// #include "custom_tuple.h"

// CUSTOM_TUPLE.h
#include <tuple>

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

    };
}
// END CUSTOM_TUPLE.h

typedef std::variant<std::string, std::tuple<int, bool>> mytype;

std::unordered_map<mytype, int> m;

int main()
{
    m[std::tuple{5, false}] = 20;
    std::cout << m[std::tuple{5, false}];
    m["hey"] = 10;
    std::cout << m["hey"];
    mytype tmp = "hey";
    std::cout << m[tmp];
}