7

For example:

struct A { void m() { } }; void stream_print() { void(A::*p)(void) = &A::m; std::cerr << p << std::endl; } void printf_print() { void(A::*p)(void) = &A::m; fprintf(stderr, "%p", p); } 

The stream_print() function always prints "1", which is obviously not what I want. The printf_print does not compile because p cannot be casted to void*.

What I need is a unique identifier for a method pointer that I can store in a container. I know this sounds like a bad idea, but I am developing a small toy for unit testing that can benefit from it. I am not worried about overloads of the method, I know how to get the pointer to a specific overload.

I am using g++ 4.4.3 with C++0x enabled.

Let me know if you have any doubts.

0

4 Answers 4

11

Member function pointer is generally an object with non-trivial internal structure. Which is why you can't print it using tools intended for printing primitive types. Casting the pointer to void * is not a viable approach, since the size of member pointer is generally larger than sizeof(void *). Forcefully casting it to void * will in any case discard a portion of the pointer representation, thus no longer guaranteeing the uniqueness.

If what you are looking for is a unique string generated from the pointer, you can reinterpret the pointer as a character array, and use the string representation of character values in the identifier. Something like

void (A::*p)(void) = &A::m; for (size_t i = 0; i < sizeof p; ++i) printf("%d ", reinterpret_cast<char *>(&p)[i]); printf("\n"); 
Sign up to request clarification or add additional context in comments.

3 Comments

@Matthieu M.: Firstly, that's plain incorrect. C does not define the conversion of function pointers to void * and, of course, make no guarantees about it. C does not define "mixed" conversions between data pointers and function pointers. You can use void (*)(void) as a generic function pointer, but not void *.
@Matthieu M.: Secondly, the question is about member function pointers, not about pointers to standalone functions, which is a different story entirely.
I agree that member functions are an entirely different story, especially because of virtual inheritance and virtual functions, which may necessitates a number of indirections to be stored. I'll remove my comments with regards to C, I thought it true, but apparently was mistaking.
4

Though I'm not 100% sure I understand the question correctly, if some mapping from a member pointer to some unique id is needed, the following code might meet the purpose:

struct A { void f() {} void g( int ) {} }; template< class T, T > char* get_unique_id() { static char dummy; return &dummy; } int main() { set< char* > s; s.insert( get_unique_id< decltype( &A::f ), &A::f >() ); s.insert( get_unique_id< decltype( &A::g ), &A::g >() ); s.insert( get_unique_id< decltype( &A::f ), &A::f >() ); s.insert( get_unique_id< decltype( &A::g ), &A::g >() ); cout<< s.size() <<endl; // prints 2 } 

The call of get_unique_id is a little lengthy though...
Presumably some macro might help to make it simpler.

Hope this helps

5 Comments

There is something to be done with template argument deduction here. Good idea though.
@AlexandreC.: Thanks! There is something to be done - Yes, possibly constexpr? Honestly, I'm not so familiar with 0x.
Doesn't need a whole lot: template<typename PMF> char* get_unique_id(PMF pmf) { static char dummy; return &dummy; } ... s.insert( get_unique_id(&A::f); }. Works for any type, not just pointers to member functions. But you could also use std::type_info
@MSalters: Thanks! However, in that case, isn't get_unique_id instantiated for each type(signature), not for each member function? If so, when there are multiple member functions with the same signature, they will have one common id...(That being said, possibly that might be OP's intent)
@Ise Wisteria: Yes, seems I may have misunderstood the intent - that why I wrote "works for any type".
1

If it only needs to work with GCC, you could use this extension to extract a function pointer from a pointer to member function.

Here is an example:

#include <iostream> #include <stdio.h> struct A { void m() { } }; typedef void (*mptr)(A*); int main() { mptr p = (mptr)(&A::m); std::cerr << (void*)p << std::endl; fprintf(stderr, "%p\n", p); } 

Compile with -Wno-pmf-conversions to suppress the warning.

Comments

0

There is no portable way to do this. But have you tried reinterpret_cast<void*>(p)?

I suspect stream_print is using std::operator<<(std::ostream&, bool), since that's the only valid conversion for a pointer-to-member type. That would explain why you get 1.

I wouldn't expect printf_print to work, even if a compiler did allow passing a pointer-to-member-function through .... There's no guarantee sizeof(p) == sizeof(void*), which is often a practical minimum for getting "expected" non-standard results from va_arg.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.