有没有办法创建由 `std::function<>` 包装的函数的哈希值?

2024-03-12

我有一个 C++ 函数,需要一个std::function作为输入参数。
具体来说,一个std::function<void (const Message&, Error)>.

在我的用例中,调用者可以绑定std::function到自由函数或成员函数。

(我没有经验std::bind or std::function,所以我发现值得注意的是,相同的对象类型,std::function<void (const Message&, Error)>,可以绑定到自由函数和成员函数——后者通过使用std::bind。我发现它很有趣,因为它似乎抽象了函数指针和成员函数指针的区别 https://isocpp.org/wiki/faq/pointers-to-members#fnptr-vs-memfnptr-types(至少给我这样的印象))

对于我的调试需要,记录一个哈希值是有用的,它是与std::function输入参数。
在这里,我很快意识到我无法逃避自由函数指针和成员函数指针之间的根本区别。
我可以获得底层void (*)(const Message&, Error)自由函数指针使用std::function::target<void (*)(const Message&, Error)>(),它作为一个独特的哈希满足我的需求。
但这不起作用,如果std::function<void (const Message&, Error)>绑定到成员函数。
在我的脑海里,我推断如果std::function<void (const Message&, Error)>被绑定到class Foo成员函数,那么std::function::target<void (Foo::*)(const Message&, Error)>()会返回指向成员函数指针的指针——但情况似乎并非如此。

这导致我的问题:有没有什么方法可以从 a 中获取唯一的哈希值std::function实例,无论它绑定到自由函数还是成员函数?

#include <functional>
#include <iostream>

using namespace std;

struct Message {
  int i_;
};

struct Error {
  char c_;
};

class Foo {
public:
  void print(const Message& m, Error e) {
    cout << "member func: " << m.i_ << " " << e.c_ << endl;
  }
};

void print(const Message& m, Error e) {
  cout << "free func: " << m.i_ << " " << e.c_ << endl;
};

void doWork(function<void (const Message&, Error)> f) {
  // I can invoke f regardless of whether it's been bound to a free function or
  // a member function...
  {
    Message m{42};
    Error e{'x'};

    f(m, e);
  }

  // ...but since I don't know whether f is bound to a free function or a member
  // function, I can't use std::function::target<>() to generically get a
  // function pointer, whose (void*) value would have served my need for a
  // hash...
  {
    typedef void (*Fptr)(const Message&, Error);
    typedef void (Foo::*Mfptr)(const Message&, Error);

    Fptr* fptr = f.target<Fptr>();
    Mfptr* mfptr = nullptr;

    cout << "free func target: " << (void*)fptr << endl;

    if (fptr) {
      cout << "free func hash: " << (void*)*fptr << endl;
    }
    else {
      // ...moreover, when f is bound to a Foo member function (using
      // std::bind), std::function::target<>() doesn't return a Foo member
      // function pointer either...I can't reason why not.
      // (this also isn't scalable because in future, f may be bound to a 
      // class Bar or class Baz member function)
      mfptr = f.target<Mfptr>();
      cout << "not a free function; checking for a Foo member function" << endl;
      cout << "member func target: " << (void*)mfptr << endl;

      if (mfptr) {
        cout << "member func hash: " << (void*)*mfptr << endl;
      }
    }
  }
}

int main()
{
  {
    function<void (const Message&, Error)> f = print;

    doWork(f);
  }

  cout << "---" << endl;

  {
    Foo foo;
    function<void (const Message&, Error)> f = bind(&Foo::print,
                                                    &foo,
                                                    placeholders::_1,
                                                    placeholders::_2);

    doWork(f);
  }

  return 0;
}

编译及输出:

$ g++ --version && g++ -g ./main.cpp && ./a.out
g++ (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

free func: 42 x
free func target: 0x7ffda4547bf0
free func hash: 0x55db499c51e5
---
member func: 42 x
free func target: 0
not a free function; checking for a Foo member function
member func target: 0

以下代码:

#include <functional>
#include <iostream>
#include <vector>
#include <string>
#include <cstdint>

int f(int a) { return -a; }
int f2(int a) { return a; }

int main() {
    std::vector<std::function<int(int)>> fn{
        f,
        f,
        f2,
        f2,
        [](int a) {return -a;},
        [](int a) {return -a;},
        [](int a) {return -a;},
    };

    for (auto&& a : fn) {
        const auto t = a.target<int(*)(int)>();
        const auto hash = t ?
            (size_t)(uintptr_t)(void*)*t :
            a.target_type().hash_code();
        std::cout << hash << '\n';
    }
}

由两个 f 函数、两个 f2 函数和 3 个 lambda 函数组成的初始化向量。因此,我们期待两个相同的哈希值,两个相同的哈希值,并且每个 lambda 都是一个新类型 - 3 个不同的哈希值。代码输出:

4198918
4198918
4198932
4198932
11513669940284151167
7180698749978361212
13008242069459866308
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法创建由 `std::function<>` 包装的函数的哈希值? 的相关文章

随机推荐