Currently in C++, we can get a function pointer with
&ns::foo or ns::foo. The problem with this is that, if
foo is overloaded, it fails to compile as it actually needs to produce a pointer to a concrete function. I find this unintuitive. To get the behavior I would expect, one would need to write:
[](auto&&... args) { return ns::foo(std::forward<decltype(args)>(args)...); }
Or in the truly general case:
[](auto&&... args) noexcept(noexcept(ns::foo(std::forward<decltype(args)>(args)...)))
-> decltype(ns::foo(std::forward<decltype(args)>(args)...)) {
return ns::foo(std::forward<decltype(args)>(args)...);
}
Or, using
Barry's Abbreviated Lambdas:
[](args...) => ns::foo(>>args...)
In that paper, it was mentioned that there is an idea floating around to make this:
I think this should be added to C++.
Which would be roughly equivalent to:
[](auto&& cls, auto&&... args) {
static_assert(std::is_same_v<ns::Class, std::decay_t<decltype(cls)>>);
return std::forward<decltype(cls)>(cls).member(std::forward<decltype(args)>(args)...);
}
But it would make sense to allow the
cls parameter to be the same as in
std::invoke (as in the Make Pointers to Members Callable paper). That is, if
cls were actually a
ns::Class*, it would work, as well as a
std::reference_wrapper<ns::Class> and the rest of the invoke protocol.
This has an immediate benefit: you can make this type of function reference to standard library objects. &std::string::size is illegal, as the standard library is allowed to have default arguments, but []std::string::size would be legal.
There are possible drawbacks. For one, what should the following be:
void foo() {}
int main() {
auto foo = []{};
auto bar = []foo;
}
Should it capture foo, call the foo function, or do something else? I'd suggest that it would call the foo function, and that if the user wanted to capture it would be:
int main() {
auto foo = []{};
auto bar = [foo]foo; // or [&foo]foo to capture by reference
}
But that might not be feasible.