2016-02-22 5 views
13

Допустим, у меня есть некоторая произвольная осложненная перегруженная функция:Определения, которое перегружает было выбрано

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. 

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

+3

Обратите внимание, что тип не достаточно отличить от перегрузки кстати. – Jarod42

+5

Я не думаю, что это возможно. Это очень похоже на основные черты типа вызова библиотеки, и последнее, как известно, требует применения магии компилятора. –

+0

@ T.C. Ах, да, вот что я подумал. [Этот] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3866.html)? – Barry

ответ

0

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

#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 Я удалю этот ответ после короткого периода, в течение которого я ожидаю, что эксперты проклинают меня. :-)

+0

Если вы собираетесь перечислить все перегрузки, вам не нужен 'choice <>'. Вы можете просто получить все перегрузки, чтобы вернуть подпись [demo] (http://coliru.stacked-crooked.com/a/49779a83d15d0e36) – Barry

+0

На самом деле, цель состоит в том, чтобы придать приоритет всем не templated функциям (как «void foo (int); '), затем к шаблонам. Таким образом вы перечисляете две специализации плюс все доступные не шаблонные функции (а не только 'int 'в вашем примере). Конечно, это можно сделать с меньшим количеством кода, а не с тем, с которым вы связаны. – skypjack

+0

Я прочитал ваш комментарий к другому ответу (* он не будет работать, если я изменю его в 'void foo (char)' *).Из-за этого я думал, что цель состоит в том, чтобы получить не шаблонную функцию, если таковая существует, в противном случае правильная специализация. «Выбор» просто помогает перебирать их. Это могло бы быть сделано с помощью какой-то 'int' /' char'-диспетчеризации, возможно, что-то еще. Во всяком случае, я надеюсь, что мне удалось объяснить, что это за цель. – skypjack

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> 
Смежные вопросы