我有一个 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