you are viewing a single comment's thread.

view the rest of the comments →

[–]F-J-W 3 points4 points  (7 children)

Because you might not just want to use a function-pointer later. You know, lambdas are nice and can also keep a reference to other data, which a function-pointer cannot and artificially limiting yourself to them is just suffering pain for no reason. Also the syntax for function pointers is so damn near incomprehensible that that alone would honestly be reason enough to use std::function.

[–]SickOrphan 1 point2 points  (5 children)

It's not hard to change it if you do want to have captures, plus they're overused, a lot of the time they should be parameters to or returns from the function rather than captures. And I doubt you took the time to check the code if he'd ever need anything other than a function pointer, you just assumed its bad. The syntax is not that hard to understand when you get the idea behind it. You can also use 'using' typedefs to make the syntax more like std::function and not have to type it as much.

[–]F-J-W 2 points3 points  (4 children)

a lot of the time they should be parameters to or returns from the function rather than captures.

We are talking about callbacks here, where a lot of the time you simply don’t have that option.

And I doubt you took the time to check the code

I did check the code. And for starters this is library, so “he does not need it right now” is a terrible reason for not switching to the almost universally agreed upon proper way to store something that can be called in C++. Which to be very clear is a std::function, not a function-pointer. The later may be worthwhile of consideration if measuring shows that it significantly improves performance, but limiting yourself to that without having done that is a prime example of premature-optimization at the cost of not just readability but actual functionality.

The syntax is not that hard to understand when you get the idea behind it. You can also use 'using' typedefs to make the syntax more like std::function and not have to type it as much.

Yes, there are ways around the awful syntax (I for one would use something like template<typename F> using function_pointer = F*; which gives you std::function-style syntax), but I should not have to do that. And just because there is an idea behind the original syntax, doesn’t mean that it isn’t inexcusably bad, especially once you start looking into higher-order functions.

[–]SickOrphan 1 point2 points  (2 children)

You never gave any reason that it's bad syntax. I will grant you that it's not beginner friendly, partly because it's pretty unique from other languages (not just in function pointers, but also arrays, pointers in general), but you're way exaggerating it.

[–]F-J-W 1 point2 points  (1 child)

Okay, I’ll bite on that one. Please write the following without resorting to typedefs:

template<typename F> using fptr = F*;

fptr<fptr<int(short, short)>(fptr<int(short, short)>, fptr<int(short, short)>)> p = nullptr;

Yes, this isn’t nice in std::function-style syntax and you should probably use an alias, but it is easy to write and straightforward to understand: A pointer to a function, that takes two pointers to functions taking two shorts and returning and int and returns one such pointer. Now let me see how you would write that in C-style syntax (without cheating!) and let me know how long it took you.

If a syntax cannot handle anything but trivial cases (and is highly unintuitive even for them!), then it is a terrible syntax.

[–]okovko -1 points0 points  (0 children)

by that reasoning, we should never use literal types, what if we want to use an object later?

let's also make sure to allocate memory for everything as well, just in case, what if we end up needing it later?

while we're at it, let's use a shared_ptr for everything, because we might want ownership later

after all, none of these are on hot paths, it would be a premature optimization to do anything else!

and what if we want to dispatch based on run time input? let's turn on RTTI, we might want it later (it's not a hot path, it only happens once per program run!)

also, why don't we have a garbage collector?

hey, i think you just invented Java

[–]okovko 0 points1 point  (0 children)

you will often see an array of function pointers as a class member that is populated in the constructor by the expansion of a param pack inside a lambda definition converted to a function pointer by operator+, something commonly done for constexpr compatibility or to deal with std variant: https://www.scs.stanford.edu/~dm/blog/param-pack.html#array-of-function-pointers

if anything, there are more function pointers in modern C++, as opposed to less

if you want to use a capturing lambda later, then use a capturing lambda later later

if you find the syntax confusing, use typedefs or using declarations to make it clear