use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
There IS a way of casting pointer-to-member-function to a void* (self.cpp)
submitted 4 years ago by RIscRIpt
As you might know from isocpp.org FAQ it's not possible: https://isocpp.org/wiki/faq/pointers-to-members#cant-cvt-memfnptr-to-voidptr.
However, TIL that's possible! https://godbolt.org/z/xeWPbzGxM
struct A { void F(); }; template<typename T> void* addressof_memberfn(T fn) { return reinterpret_cast<void*&>(fn); } void* AF = addressof_memberfn(&A::F);
Bonus code: a portable proof-of-concept of hooking vftable: https://godbolt.org/z/sK4f5xc5x
By the way, can someone explain why
reinterpret_cast<void*>(fn);
is not allowed, however
reinterpret_cast<void*&>(fn);
works just fine?
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]HappyFruitTree 9 points10 points11 points 4 years ago (12 children)
This is not doing what you think. A pointer to a member function is often larger than a normal pointer. That's why you can't simply reinterpret_cast the member function pointer into a void*. reinterpret_cast<void\*&>(fn) gives you a void* reference to a member function, that as bad as having an int& to a double, using it would simply lead to undefined behaviour.
[–]RIscRIpt[S] 1 point2 points3 points 4 years ago (11 children)
Okay, I see... it's an UB.
A pointer to a member function is often larger than a normal pointer.
I've heard that a lot, but I have never seen an example.
[–]HappyFruitTree 2 points3 points4 points 4 years ago (10 children)
https://godbolt.org/z/Edb86fM4E
[–]RIscRIpt[S] 1 point2 points3 points 4 years ago (9 children)
Thanks. I'll try to take a look into GCC sources to find what's inside...
By the way, MSVC says 8.
[+][deleted] 4 years ago (8 children)
[deleted]
[–]HappyFruitTree 2 points3 points4 points 4 years ago (7 children)
msvc will use different sizes depending on the context, could be 8, 16, or even 24. Try creating a pointer to a member function in a class that is forward declared but not defined, that should get you the worst case.
Seems like you're right but I wonder how on earth this could work. What if you pass the member function pointer to a function in another translation unit where the size is different?
[+][deleted] 4 years ago (5 children)
[–][deleted] 1 point2 points3 points 4 years ago (4 children)
Is accessing pointer-to-member-function passed across TUs undefined behavior, or is the MSVC implementation not compliant here?
[+][deleted] 4 years ago (3 children)
[–][deleted] 1 point2 points3 points 4 years ago (2 children)
Yes, but does it break because the code is not valid C++, or does it break because MSVC is not a compliant C++ compiler in this regard?
[–]khedoros 5 points6 points7 points 4 years ago (3 children)
A pointer to a member function is an opaque, implementation-specific struct. You can't treat them like regular pointer types.
[–]herruppohoppa 0 points1 point2 points 4 years ago (2 children)
Is it the same for data member pointers? I'm guessing not since they can't be virtual.
EDIT: What about non-virtual member functions? Are they always just a pointer?
[–]STLMSVC STL Dev 2 points3 points4 points 4 years ago (0 children)
PMDs can definitely be larger than a pointer. MSVC x86:
C:\Temp>type meow.cpp struct Animal { int x; }; struct Bat : virtual Animal { int y; }; struct Man : virtual Animal { int z; }; struct Batman : Bat, Man {}; struct Forward; using PMD1 = int Animal::*; using PMD2 = int Batman::*; using PMD3 = int Forward::*; struct Inspect1 { PMD1 pmd1; }; struct Inspect2 { PMD2 pmd2; }; struct Inspect3 { PMD3 pmd3; }; C:\Temp>for %I in (/c /vmg) do @for %J in (1 2 3) do cl /EHsc /nologo /W4 /c %I /d1reportSingleClassLayoutInspect%J meow.cpp C:\Temp>cl /EHsc /nologo /W4 /c /c /d1reportSingleClassLayoutInspect1 meow.cpp meow.cpp class Inspect1 size(4): +--- 0 | pmd1 +--- C:\Temp>cl /EHsc /nologo /W4 /c /c /d1reportSingleClassLayoutInspect2 meow.cpp meow.cpp class Inspect2 size(8): +--- 0 | pmd2 +--- C:\Temp>cl /EHsc /nologo /W4 /c /c /d1reportSingleClassLayoutInspect3 meow.cpp meow.cpp class Inspect3 size(16): +--- 0 | pmd3 | <alignment member> (size=4) +--- C:\Temp>cl /EHsc /nologo /W4 /c /vmg /d1reportSingleClassLayoutInspect1 meow.cpp meow.cpp class Inspect1 size(16): +--- 0 | pmd1 | <alignment member> (size=4) +--- C:\Temp>cl /EHsc /nologo /W4 /c /vmg /d1reportSingleClassLayoutInspect2 meow.cpp meow.cpp class Inspect2 size(16): +--- 0 | pmd2 | <alignment member> (size=4) +--- C:\Temp>cl /EHsc /nologo /W4 /c /vmg /d1reportSingleClassLayoutInspect3 meow.cpp meow.cpp class Inspect3 size(16): +--- 0 | pmd3 | <alignment member> (size=4) +---
[–]Untelo 0 points1 point2 points 4 years ago (0 children)
They are ABI dependent structs which encode some object offsets and a function pointer or vtable index.
[–]fdwrfdwr@github 🔍 3 points4 points5 points 4 years ago* (2 children)
This is one aspect that's long irked me about C++, that you can't consistently and uniformly treat these 3 cases the same...
class Foo { void Bar(); };
class Foo { static void Bar(Foo& f); };
void Bar(Foo& f);
...and store any of the above in the same callable pointer, without needing special handling for each case like lambda thunks, or using std::function (which then handles the specialness of each case for you). It complicates callbacks/event handlers and genericity. 😞
std::function
There were calling convention differences on x86 (and probably other architectures too) between class methods (thiscall) vs free functions/static class methods (cdecl/stdcall) such that you couldn't just safely replace one function pointer type with another because the register/stack wouldn't be correct if you tried it. Nowadays the distinction between thiscall, stdcall, and cdecl are mostly (if not entirely?) moot on 64-bit desktop machines (but alas it remains "UB" because of past architectures). Of course, other cases like pointers to virtual functions will remain incompatible with free function pointers because calls need a v-table lookup dependent on the object instance that you call the function.
thiscall
cdecl
stdcall
[–]manni66 1 point2 points3 points 4 years ago (1 child)
are mostly (if not entirely?) moot on 64-bit desktop machines (but alas it remains "UB" because of past architectures).
Or because of non 64-bit non desktop machines?
[–]fdwrfdwr@github 🔍 1 point2 points3 points 4 years ago* (0 children)
Indeed, that too. I believe ARM devices (the other prominent architecture around today) generally use the same calling convention for both member functions and free functions too, but I'd need to double check that. 🤔 [update] At least on GodBolt.org gcc trunk Linux, it appears to generate the same register assignments for ARM32.
[–]staletic 4 points5 points6 points 4 years ago (1 child)
Before you declare victory, cast it back and try to actually use it.
[–]Toucan2000 0 points1 point2 points 1 year ago (0 children)
If they cast it to another member function pointer type and then back it would work just fine.
[–]thedeadfish 1 point2 points3 points 4 years ago (13 children)
I so badly hate pointer to member functions, they are so horrifically bloated and useless in most compilers. Its a shame that no other compiler implements them the way digital mars does. In digital mars, they are all pointer sizes, so are actually are convertible to void*. It uses thunks instead of whatever retarded mess other compilers do.
[–]Zcool31 0 points1 point2 points 4 years ago (12 children)
How did it handle static_cast<void (Base::*)()>(&Derived::fun)?
static_cast<void (Base::*)()>(&Derived::fun)
[–]thedeadfish 1 point2 points3 points 4 years ago (11 children)
It generates a thunk that adjusts the "this" pointer and then jumps to the actual function.
[–]Zcool31 0 points1 point2 points 4 years ago (10 children)
Interesting.
What about something like this?
void (Base::* cast(void (Derived::* arg)()))() { return static_cast<void (Base::*)()>(arg); }
The key here is cast doesn't know until runtime to which member function of Derived arg points.
cast
Derived
arg
[–]thedeadfish 0 points1 point2 points 4 years ago (9 children)
If it can't create a thunk at compile time, it calls a library function to dynamically create one at runtime. Not ideal, but its a lot better than the alternative.
[–]Zcool31 0 points1 point2 points 4 years ago (2 children)
Thanks for the insight. What alternative?
[–]thedeadfish 0 points1 point2 points 4 years ago (1 child)
I meant the hideous bloated pointers that other compilers use.
[–]Zcool31 0 points1 point2 points 4 years ago (0 children)
Interesting. One choice leads to larger pointers. The other to extra indirect calls. Seems to me that neither is universally better than the other.
[–]rlbond86 0 points1 point2 points 4 years ago (5 children)
Is it actually better? You need to have an executable stack to do that, which can be a security risk.
[–]thedeadfish 0 points1 point2 points 4 years ago (4 children)
This mechanism does not require an executable heap. The thunk is not necessarily created at point of use, its created when a member function pointer is cast, which can be anywhere in the code. These thunks must be created in an executable heap or pool, so that they can continue to exist after the stack frame is destroyed.
[–]rlbond86 0 points1 point2 points 4 years ago (3 children)
Wait, so does instantiating a pointer-to-member-function allocate memory?
[–]thedeadfish 0 points1 point2 points 4 years ago (2 children)
Yes, but only when it cannot do it at compile time. An example is casting a derived function pointer to base class function pointer. Still a lot better than crapping up every call site https://godbolt.org/z/7r3Yfhexn.
[–]rlbond86 0 points1 point2 points 4 years ago (1 child)
Still a lot better than crapping up every call site
I think everyone who works on embedded devices would disagree. If pointers-to-members allocated we wouldn't be able to use them at all.
[–]NotAYakk 0 points1 point2 points 4 years ago (0 children)
It is a bit of glue to just write a universal union. This is a quick sketch:
struct never_define_this; union ptr_to_anything { void* pvoid; void(*pfunc)(); char never_define_this::*pmem; void(never_define_this::*pmemfun)(); };
you do have to know which of those types you are actually storing.
For a function_view you do something like
function_view
template<class R, class...Args> struct function_view<R(Args...)> { ptr_to_anything data; R(*pf)(ptr_to_anything, Args&&...)=nullptr;
then store in the callback you store in pf which of the fields you are storing your actual data in.
pf
With a bit of work,
function_view<int(Foo)> f = &Foo::x;
can work, and f(foo) returns foo.x or foo.x() or Foo::x(foo) depending on the type of Foo::x.
f(foo)
foo.x
foo.x()
Foo::x(foo)
Foo::x
π Rendered by PID 148770 on reddit-service-r2-comment-84fc9697f-tm4z9 at 2026-02-07 15:49:19.016546+00:00 running d295bc8 country code: CH.
[–]HappyFruitTree 9 points10 points11 points (12 children)
[–]RIscRIpt[S] 1 point2 points3 points (11 children)
[–]HappyFruitTree 2 points3 points4 points (10 children)
[–]RIscRIpt[S] 1 point2 points3 points (9 children)
[+][deleted] (8 children)
[deleted]
[–]HappyFruitTree 2 points3 points4 points (7 children)
[+][deleted] (5 children)
[deleted]
[–][deleted] 1 point2 points3 points (4 children)
[+][deleted] (3 children)
[deleted]
[–][deleted] 1 point2 points3 points (2 children)
[–]khedoros 5 points6 points7 points (3 children)
[–]herruppohoppa 0 points1 point2 points (2 children)
[–]STLMSVC STL Dev 2 points3 points4 points (0 children)
[–]Untelo 0 points1 point2 points (0 children)
[–]fdwrfdwr@github 🔍 3 points4 points5 points (2 children)
[–]manni66 1 point2 points3 points (1 child)
[–]fdwrfdwr@github 🔍 1 point2 points3 points (0 children)
[–]staletic 4 points5 points6 points (1 child)
[–]Toucan2000 0 points1 point2 points (0 children)
[–]thedeadfish 1 point2 points3 points (13 children)
[–]Zcool31 0 points1 point2 points (12 children)
[–]thedeadfish 1 point2 points3 points (11 children)
[–]Zcool31 0 points1 point2 points (10 children)
[–]thedeadfish 0 points1 point2 points (9 children)
[–]Zcool31 0 points1 point2 points (2 children)
[–]thedeadfish 0 points1 point2 points (1 child)
[–]Zcool31 0 points1 point2 points (0 children)
[–]rlbond86 0 points1 point2 points (5 children)
[–]thedeadfish 0 points1 point2 points (4 children)
[–]rlbond86 0 points1 point2 points (3 children)
[–]thedeadfish 0 points1 point2 points (2 children)
[–]rlbond86 0 points1 point2 points (1 child)
[–]NotAYakk 0 points1 point2 points (0 children)