Подтвердить что ты не робот

Определение выбранной перегрузки

Скажем, у меня есть какая-то произвольная сложная перегруженная функция:

template <class T> void foo(T&& );
template <class T> void foo(T* );
void foo(int );

Я хочу знать, для данного выражения, которое вызывает foo(). Например, с учетом некоторого макроса WHICH_OVERLOAD:

using T = WHICH_OVERLOAD(foo, 0);       // T is void(*)(int);
using U = WHICH_OVERLOAD(foo, "hello"); // U is void(*)(const char*);
// etc.

Я не знаю, где я буду использовать такую ​​вещь - мне просто интересно, если это возможно.

4b9b3361

Ответ 1

Барри, извините за недоразумение в моем первом ответе. Вначале я неправильно понял ваш вопрос. "Агар Т.С." правильно, что это невозможно, за исключением некоторых редких случаев, когда ваши функции имеют разные типы результатов в зависимости от данных аргументов. В таких случаях вы даже можете получить указатели на функции.

#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;
}

Вывод:

char
string
string
vector<int>
vector<int>

Ответ 2

Я, вероятно, далек от того, что вы имеете в виду, но я потратил свое время на это, и стоит добавить ответ (возможно, совершенно неверный):

#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 the invoked function
        // it 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 the invoked function
        // it 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 the invoked function
        // it 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), "!");
}

Я удалю этот ответ после непродолжительного периода, в течение которого я ожидаю, что эксперты проклинают меня.: -)