Let\'s say I have some arbitrary complicated overloaded function:
template void foo(T&& );
template void foo(T* );
vo
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. :-)
Barry, sorry for the misunderstanding in my first answer. In the beginning I understood your question in a wrong way. 'T.C.' is right, that it is not possible except in some rare cases when your functions have different result types depending on the given arguments. In such cases you can even get the pointers of the functions.
#include <string>
#include <vector>
#include <iostream>
//template <class T> T foo(T ) { std::cout << "template" << std::endl; return {}; };
std::string foo(std::string) { std::cout << "string" << std::endl; return {}; };
std::vector<int> foo(std::vector<int>) { std::cout << "vector<int>" << std::endl; return {}; };
char foo(char) { std::cout << "char" << std::endl; return {}; };
template<typename T>
struct Temp
{
using type = T (*) (T);
};
#define GET_OVERLOAD(func,param) static_cast<Temp<decltype(foo(param))>::type>(func);
int main(void)
{
auto fPtr1 = GET_OVERLOAD(foo, 0);
fPtr1({});
auto fPtr2 = GET_OVERLOAD(foo, std::string{"hello"});
fPtr2({});
auto fPtr3 = GET_OVERLOAD(foo, std::initializer_list<char>{});
fPtr3({});
auto fPtr4 = GET_OVERLOAD(foo, std::vector<int>{});
fPtr4({});
auto fPtr5 = GET_OVERLOAD(foo, std::initializer_list<int>{});
fPtr5({});
return 0;
}
The output is:
char
string
string
vector<int>
vector<int>