I want to do something like
template <typename T>
void foo(const T& t) {
IF bar(t) would compile
bar(t);
ELSE
baz(t);
}
I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can’t seem to work out the details. What’s the simplest way of achieving this?
There are two lookups that are done for the name
bar. One is the unqualified lookup at the definition context offoo. The other is argument dependent lookup at each instantiation context (but the result of the lookup at each instantiation context is not allowed to change behavior between two different instantiation contexts).To get the desired behavior, you could go and define a fallback function in a
fallbacknamespace that returns some unique typeThe
barfunction will be called if nothing else matches because the ellipsis has worst conversion cost. Now, include that candidates into your function by a using directive offallback, so thatfallback::baris included as candidate into the call tobar.Now, to see whether a call to
barresolves to your function, you will call it, and check whether the return type isflag. The return type of an otherwise chosen function could be void, so you have to do some comma operator tricks to get around that.If our function was selected then the comma operator invocation will return a reference to
int. If not or if the selected function returnedvoid, then the invocation returnsvoidin turn. Then the next invocation withflagas second argument will return a type that has sizeof 1 if our fallback was selected, and a sizeof greater 1 (the built-in comma operator will be used becausevoidis in the mix) if something else was selected.We compare the sizeof and delegate to a struct.
This solution is ambiguous if the existing function has an ellipsis too. But that seems to be rather unlikely. Test using the fallback:
And if a candidate is found using argument dependent lookup
To test unqualified lookup at definition context, let’s define the following function above
foo_implandfoo(put the foo_impl template abovefoo, so they have both the same definition context)