2017-01-15 4 views
5

Предполагая, что функция (которая может быть либо глобальной функцией, либо функцией-членом) перегружена только по ее параметрам (так что ее перегрузки всегда будут полностью const или неконстантными) , Есть ли способ написать шаблон, который будет выбирать адрес перегрузки в соответствии с указанным параметром? Например:Найти только адрес перегрузки по его параметрам

struct Foo { 
    double bar(double n, double m); 
    int bar(int n, int m); 
}; 

auto addressDouble = find_overload<&Foo::bar, double, double>::address; 
auto addressInt = find_overload<&Foo::bar, int, int>::address; 

Интересный ответ я нашел here, но, к сожалению, это дело только с переадресацией вызова на правую перегрузку, а не на самом деле выборок адреса перегрузки, так что он может быть использован позже.

Последнее примечание: идеальное решение должно работать над выпущенной версией Clang. Помимо этого требования, можно использовать любые доступные функции C++ 1z и ниже.

ответ

1

Перед тем, как получить доступ к адресу перегруженной функции вы должны определить, какая версия вам нужно.

template<typename ...TA> 
struct find_overload 
{ 
    template<typename TObj, typename TR> 
    using member_func_t = TR(TObj::*)(TA...); 

    template< typename TObj, typename TR > 
    static constexpr auto get_address(member_func_t<TObj, TR> func) -> member_func_t<TObj, TR> 
    { 
     return func; 
    } 
}; 

int main() 
{ 
    constexpr auto address = find_overload<double, double>::get_address(&Foo::bar); 
} 
+0

_which может быть либо глобальной функцией, либо функцией-членом. В ответе не рассматриваются требования к свободным функциям. – skypjack

+0

@skypjack Да, это не касается бесплатных функций, но главная цель здесь - предоставить основную идею о том, как ее можно реализовать. OP сам может изменить и расширить предоставленные решения в соответствии с его требованиями. – MRB

+0

Я не вижу причин для голосования. Лучше дать объяснение для голосов вниз. – MRB

0

Вы можете использовать static_cast<>():

auto addressDouble = static_cast<double(*)(double, double)>(&Foo:bar); 
auto addressInt = static_cast<int(*)(int, int)>(&Foo:bar); 
+0

К сожалению, использование 'static_cast' по-прежнему требует указания типа возвращаемого значения функции, что я пытался избежать –

0

Несмотря на working answer @MRB, существует более компактное решение.
вытекает минимальный, рабочий пример:

#include<iostream> 

struct Foo { 
    double bar(double n, double m) {} 
    int bar(int n, int m) {} 
}; 

double quux(double n, double m) {} 
int quux(int n, int m) {} 

template<typename... A, typename T, typename R> 
constexpr auto find_overload(R(T::*f)(A...)) { return f; } 

template<typename... A, typename R> 
constexpr auto find_overload(R(*f)(A...)) { return f; } 

int main() { 
    auto fooAddressDouble = find_overload<double, double>(&Foo::bar); 
    auto fooAddressInt = find_overload<int, int>(&Foo::bar); 
    Foo foo; 
    (foo.*fooAddressDouble)(0., 0.); 
    (foo.*fooAddressInt)(0, 0); 

    auto globalAddressDouble = find_overload<double, double>(&quux); 
    auto globalAddressInt = find_overload<int, int>(&quux); 
    globalAddressDouble(0., 0.); 
    globalAddressInt(0, 0); 
} 

Как вы можете видеть, find_overload принимает как свободные функции и функции членов (для которых он выводит тип класса, а также тип возвращаемого значения).

+0

Несмотря на свободные функции, необходимо учитывать перегрузку членов или свободных функций 'const'. – MRB

+0

@ MRB OP сказал что-то другое в вопросе на самом деле. – skypjack

Смежные вопросы