【问题标题】:Implementing a typedef function from a header into a source file in C++在 C++ 中从头文件到源文件中实现 typedef 函数
【发布时间】:2014-11-15 13:41:23
【问题描述】:

我目前正在尝试为 HashMap 类实现哈希函数。我们得到了一个 HashMap.h 文件,我们不能更改任何预定义的成员变量和函数。在为 HashMap 类实现我的 .cpp 文件时,这并没有被证明是一个挑战,直到我到达这一行:

typedef std::function<unsigned int(const std::string&)> HashFunction;

通常如果这是在我的头文件中:

HashMap();

我可以在我的源文件中这样做来实现它:

HashMap::HashMap() {
// code here
}

我的问题是如何在我的源文件中实现这个 typedef?我有我的哈希函数(hashFunc),它接受一个常量字符串,并返回一个无符号整数,如下所示:

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++ 新手,所以我意识到我可能看起来这个问题现在很愚蠢,但我不知道如何继续。

【问题讨论】:

  • “实现 typedef”是什么意思?它只是一个类型的别名。
  • 我只是想把它放在我的类源文件中。由于 HashFunction HashMap::hashFunc(const std::string& key) { // code } 不能编译,而像 int HashMap::hashFunc(const std::string& key) { // code } 这样的东西会。
  • 如果我发布的答案不充分,如果您将 HashMap.h 的内容附加到问题的末尾可能会有所帮助,这样我们就可以准确地看到您正在处理的限制。

标签: c++ function class typedef


【解决方案1】:

您可能已经意识到,std::function&lt;unsigned int(const std::string&amp;)&gt; 是一个函数类型,它在输入中接受一个字符串并返回一个 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);

【讨论】:

  • 我将把它添加为注释,因为我不想让你混淆:如果你有 C 背景,你可能会看到 std::function 变量与函数指针有一些相似之处C.
【解决方案2】:

这只是一个类型定义。没有什么可以实现的。

typedef std::function<unsigned int(const std::string&)> HashFunction;

这行说有一个类型std::function&lt;unsigned int(const std::string&amp;)&gt;,从现在开始,您可以在HashFunction 别名下引用该类型。 std::function 只是对 Callable 的封装,例如函数、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);

【讨论】:

    【解决方案3】:

    我相信这个练习的目的是让一个类更“通用” 在类的外部定义了一些类的功能代码。

    考虑这个函数(注意声明的返回值来匹配事物 你最终会回来):

    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,您都无法以任何不同的方式计算哈希。

    因此,不是总是以完全相同的方式散列密钥的某些代码行, 您应该使用 lambda 替换 // hashFunc code here 之前传递给您的 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 的实例的打印值 实际上是构造出来的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多