I want to have a LIFT(F) macro. I can write that easily enough:
#define LIFT(F) \
[&](auto&&... args) \
noexcept(noexcept((F)(std::forward<decltype(args)>(args)...))) \
-> decltype(auto) { \
return (F)(std::forward<decltype(args)>(args)...); \
}
// Now you can use `LIFT(std::max)` as a function-object.
https://godbolt.org/z/r6bY6P15T
I can similarly write one that calls F as a member function on the first argument:
#define LIFT_MEMFN(F) \
[&](auto&& self, auto&&... args) \
noexcept(noexcept(std::forward<decltype(self)>(self).F(std::forward<decltype(args)>(args)...))) \
-> decltype(auto) { \
return std::forward<decltype(self)>(self).F(std::forward<decltype(args)>(args)...); \
}
https://godbolt.org/z/1cG5YTY1W
What I would like, and I feel like might be possible with crazy SFINAE tricks but I haven't figured it out, is to write a LIFT(F) that acts like std::invoke, so if it is passed a first argument, a0, first try a0.F(args...) then trying a0->F(args...), then falling back to F(a0, args...). Is this possible?