提问人:StoneThrow 提问时间:4/27/2023 最后编辑:Gabriel StaplesStoneThrow 更新时间:4/27/2023 访问量:188
有没有办法创建由“std::function<>”包装的函数的哈希值?
Is there a way to create a hash of a function wrapped by `std::function<>`?
问:
我有一个 C++ 函数,它接受 a 作为输入参数。
具体来说,一个 .std::function
std::function<void (const Message&, Error)>
在我的用例中,调用者可以将 绑定到自由函数或成员函数。std::function
(我对 or 没有经验,所以我发现值得注意的是,相同的对象类型 ,可以绑定到自由函数和成员函数——后者通过使用 .我发现它很有趣,因为它似乎抽象出了函数指针和成员函数指针之间的区别(至少它给了我这种印象))std::bind
std::function
std::function<void (const Message&, Error)>
std::bind
对于我的调试需求,记录与输入参数关联的哈希值(唯一值)会很有用。
在这里,我很快意识到我无法逃避自由函数指针和成员函数指针之间的根本区别。
我可以使用 获取底层免费函数指针,它作为唯一哈希来满足我的需求。
但是,如果绑定到成员函数,则不起作用。
在我的脑海中,我推断,如果绑定到成员函数,那么将指针返回到成员函数指针 - 但事实似乎并非如此。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)>()
这就引出了我的问题:有没有办法从 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
评论
auto factory(int x){ return [x](int y){ return x + y;}; }
factory(10)
factory(20)
hash_code
,这有什么好处吗?target_type().name()
std::hash<std::string_view>{}(a.target_type().name())
target_type().hash_code()
*t
void*
uintptr_t
size_t
(size_t)(uintptr_t)(void*)*t
size_t
(size_t)*t
size_t
(size_t)*t
评论
std::function::target_type().name()
size_t addr = (size_t)my_func;
doWork()
std::function