I think none of these points are demonstrated in the post hence I fail to visualize it
Also I copy pasted the code from the post and I got this:
test.cpp:70:14: error: assigning to 'void ' from 'func0Ptr' (aka 'void ()(void *)') converts between void pointer and function pointer
70 | res.fn = (func0Ptr)fn;
> test.cpp:70:14: error: assigning to 'void ' from 'func0Ptr' (aka 'void ()(void *)') converts between void pointer and function pointer 70 | res.fn = (func0Ptr)fn;
This warning is stupid. It's part of the "we reserve the right to change the size of function pointers some day so that we can haz closures, so you can't assume that function pointers and data pointers are the same size m'kay?" silliness. And it is silly: because the C and C++ committees will never be able to change the size of function pointers, not backwards-compatibly. It's not that I don't wish they could. It's that they can't.
Note that conversion from a void * pointer to a function
pointer as in:
fptr = (int (*)(int))dlsym(handle, "my_function");
is not defined by the ISO C standard. This standard
requires this conversion to work correctly on conforming
implementations.
`res.fn` is of type `void *`, so that's what the code should be casting to. Casting to `func0Ptr` there seems to just be a mistake. Some compilers may allow the resulting function pointer to then implicitly convert to `void *`, but it's not valid in standard C++, hence the error.
Separately from that, if you enable -Wpedantic, you can get a warning for conversions between function and data pointers even if they do use an explicit cast, but that's not the default.
You can't just keep claiming these things without providing evidence. How much faster? How much smaller? These claims are meaningless without numbers to back it up.
Your Func thing is better than std::function the same way a hammer is better than a drill press... ie it's not better because it's not the same thing at all. Yes the hammer can do some of the same things, at a lower complexity, but it can't do all the same things.
What I'm trying to say is being better than x means you can do all the same things as x better. Your thing is not better, it is just different.
This is a valid point missed by many today. The mantra of don't optimise early is often used as an excuse to not optimise at all, and so you end up with a lot of minor choices scattered throughout the code with all suck a tiny bit of performance out of the system. Fixing any of these is also considered to be worthless, as the improvement from any one change is miniscule. But added up, they become noticeable.
> Is it because I made hundreds decisions like that? Yes.
Proof needed. Perhaps your overall program is designed to be fast and avoid silly bottlenecks, and these "hundred decisions" didn't really matter at all.
But do you have actual proof for your first claim? Isn't it possible that the "constant vigilance" is optimizing that ~10% that doesn't really matter in the end?
For example C++ can shoehorn you to a style of programming where 50% of time is spent in allocations and deallocations if your code is otherwise optimal.
The only way to get that back is not to use stl containers in ”typical patterns” but to write your own containers up to a point.
If you didn’t do that, youd see in the profiler that heap operations take 50% of time but there is no obvious hotspot.
Yours is smaller (in terms of sizeof), because std::function employs small-buffer optimization (SBO). That is if the user data fits into a specific size, then it's stored inline the std::function, instead of getting heap allocated. Yours need heap allocation for the ones that take data.
Whether yours win or lose on using less memory heavily depends on your typical closure sizes.
Smaller size at runtime (uses less memory).
Smaller generated code.
Faster at runtime.
Faster compilation times.
Smaller implementation.
Implementation that you can understand.
How is it worse?
std::function + lambda with variable capture has better ergonomics i.e. less typing.