Reputation: 57
I want to store and identify std::function
objects in a std::map
.
To identify I want to use the std::function::target
.
I can't get the pointer from std::function::target
if I use std::bind
to bind to a member function from a class.
#include <functional>
#include <iostream>
using namespace std;
void normal_fun(int a)
{
std::cout << "hello\n"<<a;
}
class testclass
{
public:
int b;
void mytest(int a)
{
b = a;
}
};
uintptr_t getFuncAddress(std::function<void(int)> &f)
{
uintptr_t returnAddress = reinterpret_cast<uintptr_t>(f.target<void(*)(int)>());
return returnAddress;
}
int main()
{
testclass c;
std::function<void(int)> f1 = bind(&testclass::mytest,&c, placeholders::_1);
std::function<void(int)> f2 = normal_fun;
auto addrF1 = getFuncAddress(f1);
auto addrF2 = getFuncAddress(f2);
}
How can I achieve what I want to do?
Upvotes: 2
Views: 3069
Reputation: 238351
f.target<void(*)(int)>
Is wrong, because the type returned by bind is not void(*)(int)
, so the target will never return a non-null pointer. Bind does not return a function pointer. It returns some object of implementation specified type.
The type can be acquired with decltype
. This is a bit perverse, but should be correct:
f.target<decltype(bind(
&testclass::mytest,
(testclass*)nullptr,
placeholders::_1)
)>
but i have the Problem that i didn't know in getFuncAddress if i have testclass or myOtherClass or someone else Class
You can only use std::function::target
if you know the type of the wrapped object. If the number of choices is limited, then you can try to get the target with each type until non-null is returned. For an arbitrary unknown type, std::function::target
can not be of any use for you.
I want to store and identify std::function objects in a std::map
I think you will have to use some external key, that cannot be extracted from the std::function
. This means that if you wish to prevent duplicates, you also need an external method of guaranteeing a unique mapping from key to the function.
Upvotes: 0
Reputation: 171293
The point of std::function
is to give a uniform interface and type for callable objects that meet a given signature. You are expecting it to also provide a uniform key for sorting, but it doesn't do that. There is no way to sort function pointers and arbitrary function objects and callables returned by std::bind
. They are completely different things, and comparing them doesn't make sense. All std::function
allows you to do is store them and call them.
If you need a sorting mechanism you'll have to invent something yourself, you won't get it from std::function
.
Upvotes: 2
Reputation: 20141
I want to store and identify std::function objects in a std::map.
I assume, you want to identify std::function
objects (e.g. to call or delete them selectively).
In such situations, I use an additional key e.g. a simple unsigned
.
A global function may be used:
typedef unsigned Key;
Key genId()
{
static Key id = 0;
return ++id;
}
Now, the std::function
objects can be paired with this key. The API may grant that access to paired std::function
objects can be done using the key exclusively.
Upvotes: 0
Reputation: 275395
A std::function
is not a function pointer. It is not even a pointer.
If you know what type is stored in a std::function
, you can get a pointer to what it stores. Note that the pointer here is not the function pointer, but a pointer to the function pointer.
If you do not know what type it stores, you cannot.
If you want <
or ==
or hash
(etc), std::function
does not provide this for you. It type erases ()
, copy, move, destruction, typeid, and cast-back-to-original.
You can use type erasure techniques to augment a std::function
with those operations; note that type erasure on binary operations is a touch trickier than type erasure is in general.
Type erasing something shouldn't be your first go-to when solving a problem, but it will solve your problem. There are articles on type erasure in SO documentation for C++. This isn't a beginner subject.
Odds are your underlying problem can be solved in a much simpler way.
In any case, using the type returned from target
to order is not a great idea, as it is a pointer to a possibly automatic storage object, or possibly heap storage object; the two of which are going to have significantly different invalidation rules under innocuous operations (like move). A SBO (small buffer optimization) target is going to move with the instance of the std::function
, while a heap-allocated one is likely to stay with the state the std::function
moves around under std::move
-like operations. This is a real mess.
Upvotes: 2