在C ++中将头文件中的typedef函数实现为源文件

时间:2014-11-15 13:41:24

标签: c++ function class typedef

我正在尝试为当前的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 ++的新手,所以我我觉得这个问题我现在看起来很愚蠢,但我不知道如何继续。

3 个答案:

答案 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只是一种类型,例如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方法中调用的函数。< / 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;
}

现在您可以使用:

构造hashmap
HashMap 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的实例 实际上是构建的。