2012-03-23 4 views
3

C++ 11 шаблонной функция, которая принимает объект аргумент функции, такие как:Продвижения C++ перегруженных функций указателя на объект функции

template <typename F, typename T> 
auto foo(F f, T x) -> decltype(f(x)) { 
    return f(x); 
} 

может взять функцию, такие как:

int succ(int i) { return i+1; } 

и применять foo к succ и получить результат 10:

foo(succ,9); 

Перегружен п УНКЦИИ не работают, sin, например, не удается:

foo(std::sin,0.5); 

в НКУ (4.7) с "не может вывести параметр шаблона F".

(Предоставление sin<double> относится только к сложным видам кстати.) Да, я могу STRUCT это право:

template <typename T> 
struct Sin { 
    T operator()(T x) { return std::sin(x); } 
}; 

с небольшим:

foo(Sin<double>(),0.5); 

Мой вопрос, есть ли альтернатива что позволяет избежать необходимости в таком новом определении; можно использовать только на сайте вызова foo?

+0

'static_cast' - одна из альтернатив, хотя явно менее идеальная. – ildjarn

+0

Что значит «грех» не работает? Он компилирует штраф –

+0

@VJovic: Что значит, что я имею в виду? Он не компилируется. Однако ваш удаленный ответ. Я не знаю почему. – user2023370

ответ

8

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

template<class F, class T> 
void foo(F f, T x){ 
    f(x); 
} 

void bar(int){} 
void bar(double){} 

int main(){ 
    foo<void(int)>(bar, 5); 
} 

Live example on Ideone.

foo будет void foo(void f(int), int x) после замены, то же самое, что и foo(void (*f)(int), int x). Это обеспечивает так называемый «контекст вызова», который позволяет компилятору выбрать правильную перегрузку. Очевидно, что это работает только хорошо, если первым параметром шаблона является функция. Чтобы обойти это ограничение, и сделать его лучше (имхо, по крайней мере), вы можете предоставить простую вспомогательную функцию:

template<class F> 
auto get_overload(F f) -> decltype(f) { return f; } 

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

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

template<class F> 
F* get_overload(F* f){ return f; } 

Это еще совсем то же самое. Единственная причина, почему первая версия не может иметь только F, так как тип возврата - F - void(int), если вы вызываете его с помощью get_overload<void(int)>(bar), а стандарт не позволяет вам возвращать функции (да, это тип функции). Функция для преобразования указателя функции (void(int) ->void(*)(int)) часть только для параметров.


Так по какой причине @VJovic удалил свой ответ, я просто изменить это:

Вы можете использовать простой лямбда вместо функции get_overload. Он будет примерно одинаковым характером длины и намного более удобным и понятным. Он также будет более эффективным, так как не задействованы никакие (функциональные) указатели, и компилятор вполне способен встроить вызов.

foo([](int i){ return bar(i); }, 5); 
+0

+1, важно отметить, что это единственное место языка, где использование выражения имеет значение Кроме того, альтернативным решением является литье указателя функции: 'foo ((void (*) (int)) bar, 5)' [это статический литье], который может использоваться как * любой аргумент шаблона. –

+0

+1 для 'get_overload'. Приятно, очень приятно, и немного более дружелюбно, чем * еще одна *' static_cast'. –

+1

+1 за то, что вы любезны и добавили ответ VJovic.: -] – ildjarn

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