int (*p)(int, int) = add;
overload resolution kicks in there.I want detailed error messages about overload resolution. Maybe not all the time: give me the executive summary ("no suitable overload of add was found") and the details if I specify some "-Woverload-detailed" option or whatever. That's a quality of implementation matter; neither ISO C nor ISO C++ spell out what diagnostics should look like and how detailed they should be.
Token-level macros are hacky cruft that shouldn't be used as the development bed for new features, period. All this stuff ignores 35 years of progress in the C dialect scene alone, not to mention 60 years of progress in general.
Above, add isn't even what is understood in computing as a "first class function". If we make it into some hacky macro, we are taking away even that second class status away from it.
That's his point: C _Generic and C++ are not the same. Which one is better was not his point, just that they're different.
The comment is loaded with judgment, and the word "better" actually occurs.
To be fair, in C++ you have to say which overload you want to point a function pointer at. So the fact that you have to specify the real function you want to point at, in C, doesn't seem unreasonable.
// Well, you do say it ... with type!
int (*ptr)(int, int) = add;
This will take the address of add(int, int) and not some other add like add(double, double). There is no explicit way to refer to one or the other.You're right in that we can't point to the collection of add functions as such. There is no generic function add of which the overloads are its implementations, such that we can have a pointer to this generic add aggregate and have ptr(a, b) be subject to overload resolution.
I think that if you want to be able to construct an object ptr out of a set of plain functions, such that ptr(a, b) chooses among those functions based on arguments, that may be doable. Just not with a plain function pointer.
Personally, when I learned about _Generic, I wondered why the C committee hadn't just adopted C++-style overloading. I'm convinced the reason is to avoid name mangling. The end result is that the programmer does the name mangling "by hand," with natural consequences for doing so.
However, there are some important points, which make _Generic both more flexible than C++ overloading in some ways, and less flexible in other ways:
* _Generic only dispatches based on a single parameter.
* _Generic doesn't have to expand to a function call; it could expand to a format string, for instance (although if a macro, FOO, expands to a string literal you can't put FOO(X) next to another string literal and expect the compiler to join the two strings).
* _Generic doesn't consider type conversions when doing the dispatching.
* _Generic dispatching can be as complex as the programmer wishes (e.g., _Generic(X), switch (sizeof(X)) ...); yes, you start with type, but you don't have to limit yourself to exact matches.
* _Generic can have a "default:" branch; this is possible in C++ but not obvious (have one overload take "..." to guarantee it will be the worst match, and only chosen when there is no other option).
It also gives, IMO, better error messages than C++. If we take OP's code and change a and b from int to long, we get:
This is better than the situation in C++ where it would say the function does not exist, and then go through every function with that name (possibly quite a lot) and say why each one doesn't work.