C++ Weekly - Ep 437 - Pointers To Overloaded Functions
ฝัง
- เผยแพร่เมื่อ 25 ส.ค. 2024
- ☟☟ Awesome T-Shirts! Sponsors! Books! ☟☟
Upcoming Workshop: C++ Best Practices, NDC TechTown, Sept 9-10, 2024
► ndctechtown.co...
Upcoming Workshop: Applied constexpr: The Power of Compile-Time Resources, C++ Under The Sea, October 10, 2024
► cppunderthesea...
Episode details: github.com/lef...
T-SHIRTS AVAILABLE!
► The best C++ T-Shirts anywhere! my-store-d16a2...
WANT MORE JASON?
► My Training Classes: emptycrate.com/...
► Follow me on twitter: / lefticus
SUPPORT THE CHANNEL
► Patreon: / lefticus
► Github Sponsors: github.com/spo...
► Paypal Donation: www.paypal.com...
GET INVOLVED
► Video Idea List: github.com/lef...
JASON'S BOOKS
► C++23 Best Practices
Leanpub Ebook: leanpub.com/cp...
► C++ Best Practices
Amazon Paperback: amzn.to/3wpAU3Z
Leanpub Ebook: leanpub.com/cp...
JASON'S PUZZLE BOOKS
► Object Lifetime Puzzlers Book 1
Amazon Paperback: amzn.to/3g6Ervj
Leanpub Ebook: leanpub.com/ob...
► Object Lifetime Puzzlers Book 2
Amazon Paperback: amzn.to/3whdUDU
Leanpub Ebook: leanpub.com/ob...
► Object Lifetime Puzzlers Book 3
Leanpub Ebook: leanpub.com/ob...
► Copy and Reference Puzzlers Book 1
Amazon Paperback: amzn.to/3g7ZVb9
Leanpub Ebook: leanpub.com/co...
► Copy and Reference Puzzlers Book 2
Amazon Paperback: amzn.to/3X1LOIx
Leanpub Ebook: leanpub.com/co...
► Copy and Reference Puzzlers Book 3
Leanpub Ebook: leanpub.com/co...
► OpCode Puzzlers Book 1
Amazon Paperback: amzn.to/3KCNJg6
Leanpub Ebook: leanpub.com/op...
RECOMMENDED BOOKS
► Bjarne Stroustrup's A Tour of C++ (now with C++20/23!): amzn.to/3X4Wypr
AWESOME PROJECTS
► The C++ Starter Project - Gets you started with Best Practices Quickly - github.com/cpp...
► C++ Best Practices Forkable Coding Standards - github.com/cpp...
O'Reilly VIDEOS
► Inheritance and Polymorphism in C++ - www.oreilly.co...
► Learning C++ Best Practices - www.oreilly.co...
7:18 Overload macro is referring directly to "callable" instead of the macro parameter.
Probably one of the reasons it's not recommended: poor compiler diagnostics, bugs go unnoticed.
This problem became more prevalent with C++20/23 views (namely transform) and the optional monadic operations, because they encorage us to pass function pointers to small things.
I worked around it by using template specializations instead of function overloads. The template is deleted for the general case, but specialized for the interesting cases. Then specifying the needed overload is easy.
For example, consider a function that translates a string to a type of integer. It would be `from_string`.
Good job Jason, you even got the phishing profiles with booty profile pictures interested in C++ :D
I ended up with a similar situation when trying to make projections for use with std::ranges- did you know that taking the address of standard library functions or members of structs is not allowed? And sometimes, the type is very complicated in how it's derived. So I ended up writing macros for calling a member function or for returning a member field. Interesting to see that I'm not the only one with this idea.
6:48 With reflections we would be able to replace this with a variable template which would take a reflection of a "function overload set" and turn that into a function object (lambda) which will forward it's arguments to that overload set. Basically we would be able to "objectify" any "free" function template and overload set Ex:
template
constexpr auto FuncObj = [](...){....};
int main(){
use_callable(FuncObj);
}
I mean it makes sense that the compiler will complain that you are trying to use (but cannot instantiate yourself) a template with a template parameter that cannot be defined in another compilation unit. The current compilation unit would not even emit code for any call operator template of the lambda and no other CU can ever emit code for it as it is undefineable there.
It would compile if one defines a struct like you did with the Lambda, as this struct is something that theoretically could be defined in another CU. (For example if the Lambda struct was in a header). If it actually is still not known in any other CU or nobody instantiate use_callable with the Lambda struct than the linker would complain in the end.
As soon as I read the title, I was like, "LAMBDAS!".
I ask to make a video with overloaded member functions references in the same format as this video.
I keep track of all the topic requests in one place so I don't lose them. Feel free to add your request to the list: github.com/lefticus/cpp_weekly/issues/
I'm working with an older Qt, and the QNetworkReply there has an error() getter method and an error(Error) signal. I wanted to connect this signal to a slot using the "new" method pointer syntax, instead of the old Qt's SIGNAL macro, but the errors the compiler gave me made me end up using the SIGNAL macro anyway. So, now all the connects all around use the method pointers, but this one is the old SIGNAL / SLOT pair, haha. And this happened like two days ago.
I swear that the old qt docs about the 2 different signal/slot syntaxes mentioned a way to deal with overloaded signals or slots. But I can't find it. All I can find is a SO answer that points to the "qOverload()" helper funtion. Or just use a static cast to help the compiler, and use the new syntax which offers type safety with no runtime overhead.
@@sledgex9 Well, I'll be damned, it was `connect(reply, static_cast(&QNetworkReply::error), this, &WebQuery::onError);` all along.
I find this approach somewhat less disappointing as it avoids static casts.
void (*selected_overload)(double) = callable;
use_callable(selected_overload);
It is fundamentally the same though. Do you mean you like the syntax better?
@@weker01 Yes, the syntax feels better. However it's two steps, so isn't ideal when you want to pass the callable to an STL algorithm without extra baggage.
--Consider the following case:
template
void foo(int){}
--a simple function template.
--that doesn't use the template parameters anywhere in its arguments or return type.
Yet, If you try to pass it as a pointer, the compiler will complain about overload ambiguity.
-- so if you say for example
auto fooPtr = &foo;
-- this is a compiler error.
-- to correct it we write.
auto fooPtr = &foo;
-- that means the template parameter participate in the overload resolution despite it is not used anywhere in the function signature!!!
Question for smart people here.
Imagine you have been passed a function pointer to foo, how can you tell which type was used in the template argument when instantiating the function??
In this example: compiler-explorer.com/z/bneh55aG6
The information is completely lost inside of "use_func" but possible to object from inside of "func" and possible from the context of "main"
It's an interesting point, and you can see it play out when you look at the mangled names of the functions.
I don't think that even reflection would help, because inside of "use_func" you only have a function pointer, and these things could be defined in different shared libraries compiled at different times.
Interesting question follows from it: does &callable has value and type? Or is it quantum object? (:
The C++ Standard could do it much much better regarding functions. Namely, instead of "implicitly converting" the "function name" directly to a function pointer it could effectively create a lambda which contains all overloads of the function. This might be very useful for the standard algoritms/ranges. For example consider applying transform(abs) to a range, of course this should work with floats, ints and other number types. Usually the pattern with surrounding the function with a lambda (Like with the macro) achieves exactly what I would like to see implicitly in the standard. Optionally, the standard could add a syntax like using a special unary operator like transform(~sum), as a parallel to the + operator for lambdas
Another comment on this video pointed out the proposal P3312 R0 Overload Set Types, which seems to do what you suggest.
I'm starting to think that compilers are secretly magic.
Feels like an oversight. Any known efforts to help make this nicer to work with?
Not that I know of, no.
Any thoughts on P3312 R0 Overload Set Types?
Interesting! It makes some pain points easier but I don't think we'll have a proper way to handle overload sets and template functions in a generic way until reflection is in the language unfortunately. The inability to extract type information from template functions without instantiating them is particularly bothersome.
@@N.... Yeah, there is p2996, which seems to be getting some traction, though with some debate around the define_class interface and code injection:
P3294 R0 Code Injection with Token Sequences
I wasn't aware of it, I'll take a look.
Seems to me it would be trivial for the standard to allow an overload set to automatically translate into a lambda that has operator() overloads for everything in the overload set. I think this would be useful, or are there downsides I'm not seeing?
The problem is sometimes you actually want the function pointer. Without adding a new keyword, there’s no easy way in the existing syntax to disambiguate “I want exactly this name” from “I want the set of things with this name.”
Reflection in 26 should, I think, make writing the OVERLOAD helper without a macro possible, but I’m not 100%, as it may require the injection features we haven’t gotten yet.
@@AruisDante Nothing that currently is a function pointer would become a lambda object. If currently using an overload set results in an error, is it really a problem if in the future it would result in a usable object instead? I don't think there would be a need to change the behavior of any existing code that compiles.
@@AruisDante We won't need injection feature because we only need to reflect overload set as meta::info object and pass it as template parameter and then reify it in the lambda body.
Raw function pointers are arguably a code smell
so sad that you haven't covered all the complications one may go through to implement the most perfect lambda wrapper for an overloaded function: `constexpr`, `noexcept`, `static`, `requires`