This previous answer shows how to apply function based on the validity of a call: here. However, it applies to two functions. I was wondering if the concept could be general
Here's another fun one for kicks, abusing overload resolution. We're going to transform each function into another function that takes a rank argument, combine all of our functions together, and then just invoke them. The selection will just fall out naturally from the overload set.
Our ranker is just this ladder of types:
template struct rank : rank { };
template <> struct rank<0> { };
We need a function transformer:
template
auto prepend_arg(F&& f) {
return [f=std::forward(f)](T, auto&&... args)
-> decltype(std::forward(f)(std::forward(args)...))
{
return std::forward(f)(std::forward(args)...);
};
}
And then:
template
decltype(auto) apply_impl(std::index_sequence,
std::index_sequence,
X&&... x)
{
auto all = std::forward_as_tuple(std::forward(x)...);
return overload(
// all of our function cases
prepend_arg>(std::get(all))...,
// base case: do nothing
[](rank<0>, auto&&...) {}
)(rank{}, std::get(all)...);
// ^^^^^^^^^^^^^^^^^^^^^^^^
// pass in all the arguments
}
template
decltype(auto) apply_on_validity(X&&... x) {
return apply_impl(
std::make_index_sequence{},
std::make_index_sequence{},
std::forward(x)...);
}
I leave overload() as an exercise.