在 C++ 中将 typedef 函数从标头实现到源文件中

Implementing a typedef function from a header into a source file in C++

本文关键字:实现 源文件 C++ 中将 typedef 函数      更新时间:2023-10-16

>我目前正在尝试为 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只是一种类型,就像intstring一样。

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_inSomething实例的打印值实际上是构造的。