Для указателей на функции вы можете просто указать, как пользователь вводит подпись:
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);
}
Живой пример на Ideone .
foo
будет void foo(void f(int), int x)
после замены, что совпадает с foo(void (*f)(int), int x)
. Это обеспечивает так называемый «контекст вызова», который позволяет компилятору выбрать правильную перегрузку. Очевидно, это работает хорошо только в том случае, если первый параметр шаблона является функцией. Чтобы обойти это ограничение и сделать его лучше (imho, atleast), вы можете предоставить простую вспомогательную функцию:
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);