The problem is the following, in C++14
:
- Let's have two functions
FV&& valid_f
,FI&& invalid_f
, and argumentsArgs&&... args
- The function
apply_on_validity
should applyvalid_f
onargs
if the expressionstd::forward<FV>(valid_f)(std::forward<Args>(args)...)
is valid - Otherwise and if
std::forward<FV>(invalid_f)(std::forward<Args>(args)...)
is a valid expression,apply_on_validity
should applyinvalid_f
onargs
- Otherwise
apply_on_validity
should do nothing
I guess the code should look like something like this:
template <class FV, class FI, class... Args, /* Some template metaprog here */>
void apply_on_validity(FV&& valid_f, FI&& invalid_f, Args&&... args)
{
// Apply valid_f by default
std::forward<FV>(valid_f)(std::forward<Args>(args)...);
}
template <class FV, class FI, class... Args, /* Some template metaprog here */>
void apply_on_validity(FV&& valid_f, FI&& invalid_f, Args&&... args)
{
// Apply invalid_f if valid_f does not work
std::forward<FV>(invalid_f)(std::forward<Args>(args)...);
}
template <class FV, class FI, class... Args, /* Some template metaprog here */>
void apply_on_validity(FV&& valid_f, FI&& invalid_f, Args&&... args)
{
// Do nothing when neither valid_f nor invalid_f work
}
But I don't really know how to do that. Any idea?
Link to the generalization here.
Take:
and then:
DEMO
Here's an alternative answer, just for kicks. We need a
static_if
:And an
is_callable
. Since you're just supporting functions, we can do it as:And then we can construct the logic in place:
First, a homebrew version of C++2a's
is_detected
:As it happens, std::result_of_t is the trait we want to test.
now can_call< Some(Sig,Goes,Here) > is true_type iff the expression you want can be called.
Now we write some compile-time if dispatch machinery.
dispatch( SomeBools... ) returns a lambda. The first of the SomeBools which is compile-time truthy (has a ::value that evaluates to true in a boolean context) determines what the returned lambda does. Call that the dispatch index.
It returns the dispatch_index'd argument to the next call, and an empty lambda if that is one-past-the-end of the list.
and done, live example.
We could make this generic to enable nary version. First index_over:
Then auto_dispatch:
with test code:
Live example
Piotr Skotnicki's answer is superb, but code like that makes me feel compelled to point out how much cleaner C++17 will be thanks to
constexpr if
and additional type traits likeis_callable
:DemoDemo*This version creates more warnings but is simpler