I'm probably far from what you have in mind, but I've spent my time on that and it's worth to add an answer (maybe a completely wrong one, indeed):
#include<type_traits>
#include<utility>
template <class T> void foo(T&&);
template <class T> void foo(T*);
void foo(int);
template<int N>
struct choice: choice<N+1> { };
template<>
struct choice<3> { };
struct find {
template<typename A>
static constexpr
auto which(A &&a) {
return which(choice<0>{}, std::forward<A>(a));
}
private:
template<typename A>
static constexpr
auto which(choice<2>, A &&) {
// do whatever you want
// here you know what's the invoked function
// it's template<typename T> void foo(T &&)
// I'm returning its type to static_assert it
return &static_cast<void(&)(A&&)>(foo);
}
template<typename A>
static constexpr
auto which(choice<1>, A *) {
// do whatever you want
// here you know what's the invoked function
// it's template<typename T> void foo(T *)
// I'm returning its type to static_assert it
return &static_cast<void(&)(A*)>(foo);
}
template<typename A>
static constexpr
auto
which(choice<0>, A a)
-> std::enable_if_t<not std::is_same<decltype(&static_cast<void(&)(A)>(foo)), decltype(which(choice<1>{}, std::forward<A>(a)))>::value, decltype(&static_cast<void(&)(A)>(foo))>
{
// do whatever you want
// here you know what's the invoked function
// it's void foo(int)
// I'm returning its type to static_assert it
return &foo;
}
};
int main() {
float f = .42;
static_assert(find::which(0) == &static_cast<void(&)(int)>(foo), "!");
static_assert(find::which("hello") == &static_cast<void(&)(const char *)>(foo), "!");
static_assert(find::which(f) == &static_cast<void(&)(float&)>(foo), "!");
static_assert(find::which(.42) == &static_cast<void(&)(double&&)>(foo), "!");
}
I'll delete this answer after a short period during the which I expect experts to curse me. :-)