Is there a way to detect deleted functions after overload selection (over no viable or ambiguous overloads)?
void foo();
void foo(double) = delete;
void foo(std::string);
void foo(char, int);
void foo(int, char);
static_assert(!foo_is_deleted<>); // exist as not deleted
static_assert( foo_is_deleted<double>); // explicitly deleted
static_assert( foo_is_deleted<float>); // foo(4.2f) selects foo(double) which is deleted.
static_assert(!foo_is_deleted<const char*>); // foo("..") selects foo(std::string) which is not deleted.
static_assert(!foo_is_deleted<std::vector<int>>); // No viable overload, so not deleted
static_assert(!foo_is_deleted<char, char>); // ambiguous overload, so not deleted
The following isn't correct since it can't differentiate an ambiguous overload resolution from a deleted overload result. And I can't think of a way to differentiate that.
I'll leave my previous answer up for reference below.
Maybe something like this (https://godbolt.org/z/hTsq5rYnq):
The idea is to first test whether overload resolution succeeds with a usable candidate (meaning non-deleted) for
a.Then I make the overload
foo_is_deleted_impl::foovisible to unqualified name lookup inside the lambda withusing namespaceand repeat the test forb. The overload is declared in such a way that I think it is impossible for it to be better candidate than any other overload (If someone spots a case I missed, let me know).If
ais true, then a deleted overload surely wasn't taken, so I returnfalse.If
ais not true, butbis, then overload resolution must have had failed fora, because the overload chosen forbwouldn't be better than an overload chosen fora, and so againfalseis returned.If both
aandbare false, then there are two possibilities: Eitherbfailed because one of the non-foo_is_deleted_impl::foooverloads was chosen and is deleted, in which case I returntrue, or it failed because overload resolution became ambiguous withfoo_is_deleted_impl::foo. That means however that overload resolution foradid find a viable candidate and so its result should be returned.For all of this it is important that relative to one-another with respect to scope
foo,foo_is_deleted_implandfoo_is_deletedare placed as they are. The placement offoo_is_deletedbelow the declarations offoois also important because only ADL will lookup from the point of instantiation.This also assumes that
foois an overload set of free function (templates) called with unqualified name. It should work with ADL.