在 C++ 中将 typedef 函数从标头实现到源文件中
Implementing a typedef function from a header into a source file in C++
>我目前正在尝试为 HashMap 类实现哈希函数。我们得到了一个 HashMap.h 文件,我们不能更改任何预定义的成员变量和函数。在为 HashMap 类实现我的 .cpp 文件时,这并没有被证明是一个挑战,直到我到了这一行:
typedef std::function<unsigned int(const std::string&)> HashFunction;
通常,如果这在我的头文件中:
HashMap();
我可以在我的源文件中执行此操作来实现它:
HashMap::HashMap() {
// code here
}
我的问题是如何在源文件中实现此 typedef?我有我的哈希函数 (hashFunc),它接受一个 const 字符串,并返回一个无符号的 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++新手,所以我意识到我现在可能对这个问题看起来很愚蠢,但我不知道如何进行。
已经意识到,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
方法中调用的函数。
此时,您可能想知道如何创建类型为 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;
}
现在,您可以使用以下命令构建哈希图:
HashMap map(DJB_hash);
它只是一个typedef。没有什么要实现的。
typedef std::function<unsigned int(const std::string&)> HashFunction;
该行说有一个类型std::function<unsigned int(const std::string&)>
,从现在开始,您可以在HashFunction
别名下引用该类型。 std::function
只是对可调用的东西的包装器,例如函数、lambda、函子等。假设您有一个函数接受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);
这个练习的目的是通过以下方法使类更"通用"在类外部定义类的一些函数代码。
考虑这个函数(注意声明的返回值必须与事物匹配你最终会回来):
unsigned int HashMap::hashFunc(const std::string& key)
{
unsigned int hashValue = 0; // what we end up returning
// hashFunc code here
return hashValue;
}
如果您在不使用std::function
的情况下实现HashMap
,你可以用几行代码替换// hashFunc code here
,例如
hashValue = static_cast<unsigned int>(key[0]);
这是一个可怕的哈希函数,但它说明了这一点,即函数HashMap::hashFunc
有一个非常预定的方法来计算哈希。每当使用 HashMap
时,您永远无法以任何不同的方式计算哈希。
因此,而不是总是以完全相同的方式散列密钥的一些代码行,您应该将// hashFunc code here
替换为使用 lambda之前已传递到HashMap
构造函数并由其存储。这样,而不是在编写HashMap
本身的代码时定义,对字符串进行哈希处理的函数是在构造HashMap
实例。
所以你需要存储一个lambda(大概是HashMap
的成员)当您在 HashMap
中散列密钥时,您需要使用它.
由于通过示例学习通常比通过抽象定义更容易,这是一个打印数字 17 的玩具程序(在 http://ideone.com/年测试)以一种极其复杂的方式:
#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
并不"知道"如何计算。从输入整数value_in
到Something
实例的打印值实际上是构造的。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 为测试目标创建具有不同源文件夹的文件
- 如何正确实现和访问运算符的各种自定义枚举器
- C++:实现定义了可接受的物理源文件字符
- C 在多个源文件中包含具有同一类实现的不同标题文件
- 制作:没有实现目标的规则 - 找不到源文件
- 如何在源文件中实现嵌套类构造函数
- C++头文件中定义类,并在源文件中实现其成员
- Qt:LNK2001和LNK2019 跨源文件实现信号/时隙后会出现错误
- 在 C++ 中将 typedef 函数从标头实现到源文件中
- C++头文件和源文件的设计实现
- 使用头/源文件来分离接口和实现
- 静态库头文件包括其他头文件。我是否需要这些头文件的实现/源文件?