gpt4 book ai didi

c++ - 如何在 C++ 编译器时动态获取元组内的变量类型?

转载 作者:行者123 更新时间:2023-11-27 22:33:09 24 4
gpt4 key购买 nike

我正在尝试编写一个类型哈希函数,以在我将在程序运行时使用的哈希表中使用。

但我遇到了一个问题,要使用 constexpr std::hash() 函数。我想动态枚举我的元组值,但我无法通过在我的运算符重载方法中指定 constexpr 来做到这一点。

我做错了什么?

#include <iostream>
#include <unordered_map>

using llong = long long;
using ullong = unsigned long long;
using tlong = std::tuple<llong, llong>;
using tllong = std::tuple<llong, llong, llong>;
using tlllong = std::tuple<llong, llong, llong, llong>;
using tulong = std::tuple<ullong, ullong>;
using tullong = std::tuple<ullong, ullong, ullong>;
using tulllong = std::tuple<ullong, ullong, ullong, ullong>;

template<class Args>
struct KeyHash
{
constexpr std::size_t operator()(const Args &args) const
{
std::size_t seed = 1, _size = std::tuple_size<Args>::value;
for(auto i = 0ul; i< _size; i++)
{
seed += std::hash<std::tuple_element<(const std::size_t)i, Args>::type>()(std::get<i>(args)) + 0x2e3dbcd34 + (seed << 6) + (seed >> 4);
}

return seed;
}
};

template<class Args>
struct KeyEqual
{
bool operator()(const Args &v1, const Args &v2) const
{
return (v1 == v2);
}
};

using umtlong = std::unordered_map<tlong, int, KeyHash<tlong>, KeyEqual<tlong>>;
using umtllong = std::unordered_map<tllong, int, KeyHash<tllong>, KeyEqual<tllong>>;
using umtlllong = std::unordered_map<tlllong, int, KeyHash<tlllong>, KeyEqual<tlllong>>;

using umtulong = std::unordered_map<tulong, int, KeyHash<tlong>, KeyEqual<tlong>>;
using umtullong = std::unordered_map<tullong, int, KeyHash<tllong>, KeyEqual<tllong>>;
using umtulllong = std::unordered_map<tulllong, int, KeyHash<tlllong>, KeyEqual<tlllong>>;

int main()
{
return 0;
}

错误,我这里是

g++ hash-map-tuple-keys.cc -o hash-map-tuple-keys.o -std=c++17
hash-map-tuple-keys.cc:21:50: error: non-type template argument is not a constant expression
seed += std::hash<std::tuple_element<(const std::size_t)i, Args>::type>()(std::get<i>(args)) + 0x2e3dbcd34 + (seed << 6) + (seed >> 4);
^~~~~~~~~~~~~~~~~~~~
hash-map-tuple-keys.cc:21:69: note: read of non-const variable 'i' is not allowed in a constant expression
seed += std::hash<std::tuple_element<(const std::size_t)i, Args>::type>()(std::get<i>(args)) + 0x2e3dbcd34 + (seed << 6) + (seed >> 4);
^
hash-map-tuple-keys.cc:19:18: note: declared here
for(auto i = 0ul; i< _size; i++)
^
1 error generated.

最佳答案

constexpr 中的表达式函数,即使被评估为常量表达式,仍然必须具有静态类型。因此你不能使用 for循环,期望它在每次迭代中对不同类型进行操作。

您可以改用折叠表达式(假设为 C++17)。但要这样做,你需要一个参数包。例如,您可以通过调用 std::apply 来获得它(在元组的情况下)使用通用 lambda。

在下面的代码中,我使用了 KeyHash 的部分特化。除了std::apply , 但这主要是为了方便,所以我有 Args并且不需要使用 std::remove_reference_t<decltype(args)>而不是在 lambda 中。

template<class>
struct KeyHash;

template<class... Args>
struct KeyHash<std::tuple<Args...>>
{
constexpr std::size_t operator()(const std::tuple<Args...> &args) const
{
std::size_t seed = 1;
std::apply([&](const auto&... args){
(..., (seed += std::hash<Args>()(args) + 0x2e3dbcd34 + (seed << 6) + (seed >> 4)));
}, args);
return seed;
}
};

而不是 std::apply你也可以使用 std::integer_sequence .感谢@super 使用它来修复我以前错误的代码:

template<class Args, class I = std::make_index_sequence<std::tuple_size_v<Args>>>
struct KeyHash;

template<class... Args, std::size_t... Is>
struct KeyHash<std::tuple<Args...>, std::index_sequence<Is...>>
{
constexpr std::size_t operator()(const std::tuple<Args...> &args) const
{
std::size_t seed = 1;
(..., (seed += std::hash<Args>()(std::get<Is>(args)) + 0x2e3dbcd34 + (seed << 6) + (seed >> 4)));
return seed;
}
};

关于c++ - 如何在 C++ 编译器时动态获取元组内的变量类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58469808/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com