我正在尝试为当前的HashMap类实现哈希函数。我们得到了一个HashMap.h文件,我们不能更改任何预定义的成员变量和函数。在为HashMap类实现我的.cpp文件时,这并没有被证明是一个挑战,直到我到达这一行:
typedef std::function<unsigned int(const std::string&)> HashFunction;
通常如果这是在我的头文件中:
HashMap();
我可以在源文件中执行此操作来实现它:
HashMap::HashMap() {
// code here
}
我的问题是如何在源文件中实现此typedef?我有我的哈希函数(hashFunc),它接受一个const字符串,并返回一个unsigned int,如下所示:
HashMap::hashFunc(const std::string& key)
{
unsigned int hashValue = 0; // what we end up returning
// hashFunc code here
return hashValue;
}
但是因为我必须在我的源文件中的构造函数,复制器等中使用这个哈希函数,所以我应该从这个typedef声明它。例如,像:
HashMap::HashMap(HashFunction hashFunc) { }
我该如何使这项工作?我尝试过像HashFunction HashMap :: hashFunc(),HashMap :: HashFunction hashFunc()和HashMap :: HashFunction :: hashFunc()这样的东西,但没有任何作用:(我是C ++的新手,所以我我觉得这个问题我现在看起来很愚蠢,但我不知道如何继续。
答案 0 :(得分:1)
这只是一个typedef。没有什么可以实现的。
typedef std::function<unsigned int(const std::string&)> HashFunction;
该行说明类型为std::function<unsigned int(const std::string&)>
,从现在开始,您可以在HashFunction
别名下引用该类型。 std::function
只是函数,lambda,仿函数等Callable的包装。想象一下,你有一个函数接受HashFunction
参数并立即调用它。
void foo(HashFunction func)
{
unsigned int hashed_string = func("hello");
}
如上所述,有几种方法可以调用foo
函数。
unsigned int my_hash_func(const std::string& key)
{
// do something with key
return 42;
}
// With function pointer
foo(&my_hash_func);
// With lambda
foo([](const std::string& key) {
// do something with key
return 42;
});
当你有一个类及其构造函数需要HashFunction
时,同样适用。
class HashMap
{
HashFunction hash_func_;
public:
HashMap(HashFunction hash_func) : hash_func_(hash_func)
{}
};
HashMap m(&my_hash_func);
答案 1 :(得分:1)
您可能已经意识到,std::function<unsigned int(const std::string&)>
是一个函数的类型,它在输入中输入一个字符串并返回unsigned int
,用作地图的哈希函数。
typedef
允许您识别“任何带字符串的函数并返回未签名的”。此时,HashFunction
只是一种类型,例如int
或string
。
HashMap
的构造函数可以使用类型HashFunction
的参数来指定哈希函数,如:
class HashMap {
public:
explicit HashMap(const HashFunction &h): hash(h) {}
//...
void put(std::string element) {
unsigned int h = hash(element);
//...
}
//...
private:
HashFunction hash;
}
如您所见,我已声明hash
类型的变量HashFunction
,其中 是您可以在HashMap::put
方法中调用的函数。< / p>
此时您可能想知道如何创建类型为HashFunction
的内容。嗯,最简单的答案是:通过定义一个“标准”函数,其签名与HashFunction
的签名匹配。例如,这是一个DJB哈希:
unsigned int DJB_hash(const std::string &s) {
unsigned int h = 5318;
for (char c: s) {
h = 33 * h + c;
}
return h;
}
或者,在C ++ 11之前:
unsigned int DJB_hash(const std::string &s) {
unsigned int h = 5318;
for (int i = 0; i < s.size(); ++i) {
h = 33 * h + s[i];
}
return h;
}
现在您可以使用:
构造hashmapHashMap map(DJB_hash);
答案 2 :(得分:1)
我相信这个练习的目的是让课程更加通用&#34;通过 定义类的一些类的函数代码 。
考虑这个函数(注意声明的返回值有来匹配这个东西 你最终回来了):
unsigned int HashMap::hashFunc(const std::string& key)
{
unsigned int hashValue = 0; // what we end up returning
// hashFunc code here
return hashValue;
}
如果您在不使用HashMap
的情况下实施std::function
,
你可以用几行代码替换// hashFunc code here
,
例如
hashValue = static_cast<unsigned int>(key[0]);
这是一个可怕的哈希函数,但它说明了这一点
函数HashMap::hashFunc
有一种非常预定的方式来计算哈希值。
无论何时使用HashMap
,都不能以任何不同的方式计算哈希值。
因此,而不是总是以完全相同的方式散列键的一些代码行,
您应该使用 lambda 替换// hashFunc code here
之前已传递到HashMap
构造函数并由其存储的文件。
这样,而不是在编写HashMap
本身的代码时定义,
哈希字符串的函数在构造时确定
HashMap
的实例。
所以你需要存储一个lambda(大概是HashMap
的成员)
并且在HashMap
中散列键时需要使用它。
由于通过示例比通过抽象定义更容易学习, 这是一个玩具程序(在http://ideone.com/测试)打印数字17 以极其复杂的方式:
#include <functional>
#include <iostream>
typedef std::function<int(int)> Transformation;
class Something
{
public:
Something(Transformation transformation_in, int value_in)
: transform(transformation_in)
{
int value_out = transform(value_in);
std::cout << value_out << std::endl;
}
private:
Transformation transform;
};
Transformation increment_by_one = [](int value_in){ return value_in + 1; };
int main() {
Something something(increment_by_one, 16);
return 0;
}
在这段代码中,lambda在构造函数中使用,但当然可以
稍后在该类的另一个函数中使用,因为它存储为类成员。
关键是班级Something
不知道&#34;如何计算
输入整数value_in
中的打印值,直到Something
的实例
实际上是构建的。