How can i hash (std::tr1::hash or boost::hash) a c++ pointer-to-member-function?
Example:
I have several bool (Class::*functionPointer)() (not static) that point to several diferent methods of the class Class and i need to hash those pointer-to-member-function.
How can i do that?
Also how can i compare (std::less) those member function pointers so i can store them in a std::set?
All C++ objects, including pointers to member functions, are represented in memory as an array of chars. So you could try:
bool (Class::*fn_ptr)() = &Class::whatever;
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr));
Now treat ptrptr as pointing to an array of (sizeof(bool (Class::*)())) bytes, and hash or compare those bytes. You can use unsigned char instead of char if you prefer.
This guarantees no false positives - in C++03, pointers to member functions are POD, which means among other things that they can be copied using memcpy. This implies that if have the same byte-for-byte values, then they are the same.
The problem is that the storage representation of member function pointers could include bits which do not participate in the value - so they will not necessarily be the same for different pointers to the same member function. Or the compiler might, for some obscure reason, have more than one way of pointing to the same function of the same class, which are not byte-wise equal. Either way you can get false negatives. You'll have to look into how member function pointers actually work on your implementation. It must implement operator== for member function pointers somehow, and if you can find out how then you can probably figure out an order and a hash function.
That's potentially hard: member function pointers are awkward, and the storage is likely to include different amounts of non-participating "slack space" according to what kind of function is pointed to (virtual, inherited). So you'll probably have to interact quite significantly with your compiler's implementation details. This article might help get you started: http://www.codeproject.com/KB/cpp/FastDelegate.aspx
A cleaner alternative might be to do a linear search through an array in order to "canonicalise" all your function pointers, then compare and hash based on the position of the "canonical" instance of that function pointer in your array. Depends what your performance requirements are. And even if there are requirements, does the class (and its derived classes) have so many functions that the linear search will take that long?
typedef bool (Class::*func)();
vector<func> canon;
size_t getIndexOf(func fn_ptr) {
vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr);
if (it != canon.end()) return it - canon.begin();
canon.push_back(func);
return canon.size() - 1;
}
I could not cast the pointer (in Microsoft compiler 2010)as described in previous answer but this works for me:
static string fmptostr(int atype::*opt)
{
char buf[sizeof(opt)];
memcpy(&buf,&opt,sizeof(opt));
return string(buf,sizeof(opt));
}
About bitwise identity of the pointer, it can be bitwise so it seems if appropriate compiler switches are used. At least this is true for Microsoft compiler E.g
using #pragma pointers_to_members
and a switch.../vmg
If your member function pointer is unique, which is true in most of cases for callback-based subscriptions, then you can use the tick with type_index, which uniqueness is guaranteed by uniqueness of type (i.e. Class::Method) in your program, and it is suitable to be stored in unordered_map, i.e.
struct MyEvent {
using fn_t = std::function<void(MyEvent &)>;
using map_t = std::unordered_map<std::type_index, fn_t>;
template <typename Handler>
void subscribe(Object& obj, Handler&& handler) {
fn_t fn = [&, handler = std::move(handler)](MyEvent& event) {
(obj.*handler)(event);
}
std::type_index index = typeid(Handler);
subscribers.emplace(std::move(index), std::move(fn));
}
void fire() {
for(auto& pair: subscribers) {
auto& fn = pair.second;
fn(*this);
}
}
map_t subscribers;
}
And the subscription and fire event example:
MyEvent event;
MyObject obj = ...;
event.subscribe(obj, &MyObject::on_event );
...
event.fire();
So, example above gives you class/method uniqueness, and if you need object/method uniqueness, then you should have an struct, which provides combined hash, assuming that there is std::hash<MyObject> and there is already std::hash<std::type_index> for a member function pointer.
Related
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?
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.
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.
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.
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.
How can i hash (std::tr1::hash or boost::hash) a c++ pointer-to-member-function?
Example:
I have several bool (Class::*functionPointer)() (not static) that point to several diferent methods of the class Class and i need to hash those pointer-to-member-function.
How can i do that?
Also how can i compare (std::less) those member function pointers so i can store them in a std::set?
All C++ objects, including pointers to member functions, are represented in memory as an array of chars. So you could try:
bool (Class::*fn_ptr)() = &Class::whatever;
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr));
Now treat ptrptr as pointing to an array of (sizeof(bool (Class::*)())) bytes, and hash or compare those bytes. You can use unsigned char instead of char if you prefer.
This guarantees no false positives - in C++03, pointers to member functions are POD, which means among other things that they can be copied using memcpy. This implies that if have the same byte-for-byte values, then they are the same.
The problem is that the storage representation of member function pointers could include bits which do not participate in the value - so they will not necessarily be the same for different pointers to the same member function. Or the compiler might, for some obscure reason, have more than one way of pointing to the same function of the same class, which are not byte-wise equal. Either way you can get false negatives. You'll have to look into how member function pointers actually work on your implementation. It must implement operator== for member function pointers somehow, and if you can find out how then you can probably figure out an order and a hash function.
That's potentially hard: member function pointers are awkward, and the storage is likely to include different amounts of non-participating "slack space" according to what kind of function is pointed to (virtual, inherited). So you'll probably have to interact quite significantly with your compiler's implementation details. This article might help get you started: http://www.codeproject.com/KB/cpp/FastDelegate.aspx
A cleaner alternative might be to do a linear search through an array in order to "canonicalise" all your function pointers, then compare and hash based on the position of the "canonical" instance of that function pointer in your array. Depends what your performance requirements are. And even if there are requirements, does the class (and its derived classes) have so many functions that the linear search will take that long?
typedef bool (Class::*func)();
vector<func> canon;
size_t getIndexOf(func fn_ptr) {
vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr);
if (it != canon.end()) return it - canon.begin();
canon.push_back(func);
return canon.size() - 1;
}
I could not cast the pointer (in Microsoft compiler 2010)as described in previous answer but this works for me:
static string fmptostr(int atype::*opt)
{
char buf[sizeof(opt)];
memcpy(&buf,&opt,sizeof(opt));
return string(buf,sizeof(opt));
}
About bitwise identity of the pointer, it can be bitwise so it seems if appropriate compiler switches are used. At least this is true for Microsoft compiler E.g
using #pragma pointers_to_members
and a switch.../vmg
If your member function pointer is unique, which is true in most of cases for callback-based subscriptions, then you can use the tick with type_index, which uniqueness is guaranteed by uniqueness of type (i.e. Class::Method) in your program, and it is suitable to be stored in unordered_map, i.e.
struct MyEvent {
using fn_t = std::function<void(MyEvent &)>;
using map_t = std::unordered_map<std::type_index, fn_t>;
template <typename Handler>
void subscribe(Object& obj, Handler&& handler) {
fn_t fn = [&, handler = std::move(handler)](MyEvent& event) {
(obj.*handler)(event);
}
std::type_index index = typeid(Handler);
subscribers.emplace(std::move(index), std::move(fn));
}
void fire() {
for(auto& pair: subscribers) {
auto& fn = pair.second;
fn(*this);
}
}
map_t subscribers;
}
And the subscription and fire event example:
MyEvent event;
MyObject obj = ...;
event.subscribe(obj, &MyObject::on_event );
...
event.fire();
So, example above gives you class/method uniqueness, and if you need object/method uniqueness, then you should have an struct, which provides combined hash, assuming that there is std::hash<MyObject> and there is already std::hash<std::type_index> for a member function pointer.
I have a C++ class, and one of its fields is a std::set of objects. I want to write my own comparison function, or let the user specify one. In C++11 there's a new way to handle generic function types: std::function. It works with function pointers, member function pointers, lambda functions, etc.
I tried to write a simple experiment program but it keeps craching all the time, even when I do what the C++11 Wikipedia article suggets. Maybe I just don't get how std::function and std::ref are supposed to be used.
Anyway, the point is that when I created a std::function from a simple lambda function and made it a class member, the sizeof of the class grew by 22. When I created a std::function from a pointer to a global function, this std::function's sizeof was 32. So the size is big. I'm going to have many objects using the same comparison function, so I prefer to have one function used by all of them.
I have two ideas, tell me what you think. One idea, use std::ref to store a reference to a function, this way I can define one function and many objects will use it to compare the std::set elements. Second idea: if it doesn't work like that, or the resulting function object is too big anyway, maybe I can use a shared_ptr.
You may wonder: why not have one static std::function member? The answer: because then ALL objects will use the same comparison function. I want to be able to have, for example, 1000 objects, with 400 using one comparison function and 600 using a different comparison function.
Example:
class MyClass
{
public:
private:
std::function<bool (int, int)> compare;
std::set<int> set;
};
Now how do I make the std::set use the std::function, and have many MyClass objects use the same function?
I'd like to be able to change the comparison function during run-time, so that the user would be able to choose the ordering of the objects in the set (which are displayed by GUI).
The standard way to represent shared ownership is using std::shared_ptr. That adds a bit more overhead, forcing you to allocate the std::function on the heap, but a shared_ptr is smaller than a std::function and it will correctly manage its lifetime so while any objects are still using the function object it will be kept alive and will automatically be destroyed when no longer needed.
As you suggest, a reference_wrapper referring to the shared function can be used as the set's comparison object, because a reference_wrapper is callable if it wraps a callable type.
class MyClass
{
typedef std::function<bool (int, int)> func_type;
public:
MyClass(std::shared_ptr<func_type> const& f)
: compare(f), set( std::ref(*f) )
{ }
private:
std::shared_ptr<func_type> compare;
std::set<int, std::reference_wrapper<func_type>> set;
};
A reference_wrapper cannot be null (like a reference) so you must construct the std::set with a valid reference_wrapper object.
Since the std::reference_wrapper in the std::set just holds a non-owning pointer to the std::function, you need to be careful to update the set's comparison object at the same time as updating the shared_ptr, or you could drop the last reference to the function, so the shared_ptr would destroy it, leaving a dangling pointer in the set. That could be done like this:
void MyClass::replace_cmp(std::shared_ptr<func_type> const& f)
{
set = std::set<int, std::reference_wrapper<func_type>>( std::ref(*f) );
compare = f;
}
You tell the set to use your comparison function in your constructor initializer list:
class MyClass
{
public:
template<typename Fc>
MyClass(Fc compare_func)
: compare(compare_func), // Initialize the comparison function
set(compare) // Tell the set to use out function for comparison
{}
};
I'd like to store a series of pointers in an std::unordered_set. I'd like the hash function to be based not on the memory address, but on some values contained within the actual object referenced by the pointer.
e.g. (using std and boost namespaces for readability)
class MyClass {
...
//some values I want to use as the key for the hash
double a;
int b;
int c;
}
typedef shared_ptr<MyClass> MyClassPtr;
set<MyClassPtr> mySet;
I'm not worried about combining the actual hash values (found answer here: http://www.boost.org/doc/libs/1_47_0/doc/html/hash/combine.html), but rather dereferencing the shared_ptr to get the keys.
The other concern I have is that the == operator is already definied for boost::shared_ptr, and I was wondering if this would cause problems with my approach? I'd need to test equality against the object, not the pointer.
Storing pointers in the set because several other parts of the code are referencing the objects via their own pointers. Any alternative approaches are welcomed as well.
Thanks
What's the problem? Define a hash function and equality and on you go:
struct MyClassHash
{
inline std::size_t operator()(const MyClassPtr & p)
{
return 4; // prone to hash collisions, improve on this
}
};
struct MyClassEqual
{
inline bool operator()(const MyClassPtr & p, const MyClassPtr & q)
{
return false; // implement
}
};
typedef std::unordered_set<MyClassPtr, MyClassHash, MyClassEqual> MySet;
Note that the two functors (hash and equality) have to be written as classes; free functions don't work. (The container keeps a private instance of the functors around.) This is somewhat annoying, but since you'll only be doing this once, it shouldn't be so bad.
Normally I'd recommend specializing std::hash and std::equals, but I'd hesitate to do that with something so general as a shared pointer, since it might easily confuse others who don't expect those specializations.
In C++, is it possible to define a sort order for pointers to member functions? It seems that the operator< is undefined. Also, it's illegal to cast to void*.
class A
{
public:
void Test1(){}
void Test2(){}
};
int main()
{
void (A::* const one)() = &A::Test1;
void (A::* const two)() = &A::Test2;
bool equal = one == two; //Equality works fine.
bool less = one < two; //Less than doesn't.
return 0;
}
Thanks!
Function pointers are not relationally comparable in C++. Equality comparisons are supported, except for situations when at least one of the pointers actually points to a virtual member function (in which case the result is unspecified).
Of course, you can always introduce an ordering by implementing a comparison predicate and comparing the pointers explicitly (won't look too elegant though, since you can only use equality comparisons). Other possible solutions would cross into the territory of the various implementation-specific "hacks".
Member function pointers are not actual pointers. You should look at them as opaque structs. What does a method pointer contain:
struct method_pointer {
bool method_is_virtual;
union {
unsigned vtable_offset; // for a virtual function, need the vtable entry
void* function_pointer; // otherwise need the pointer to the concrete method
}
};
If you could cast this to void* (you can't) all you would have is a pointer the the struct, not a pointer to code. That's why operator<() is undefined as well since the value of the struct's pointer is just where ever it happens to be in memory.
In addition to that, what are you sorting by?