Вы можете просто разрешить функции принимать любой тип, будь то указатель функции или лямбда:
template<typename F, typename... Args>
void do_test(F f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
В зависимости от вашего варианта использования, рассмотрите возможность использования f
by- const
-ссылки или ссылка на пересылку (т.е. F&&
), а также.
Вам также следует рассмотреть возможность изменения способа, которым вы принимаете параметры функции args
. Обычно в такой ситуации вы берете их по , перенаправляя ссылку , что означает Args&&... args
вместо Args&... args
. В противном случае вы не сможете вызывать функцию с аргументами rvalues.
Или, если у вас есть какая-то конкретная c причина принять только один указанный c тип указателя на функцию, вы можете сделать первый параметр функции - это не выводимый контекст, учитывая, что аргументы шаблона уже могут быть выведены из других параметров функции:
template<typename... Args>
void do_test(std::type_identity_t<Func<Args&...>> f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
std::type_identity_t
является функцией C ++ 20, но может быть легко реализована :
template<typename T>
struct type_identity {
using type = T;
};
template<typename T>
using type_identity_t = typename type_identity<T>::type;
Все, что осталось для оператора разрешения области действия ::
в type_identity<T>::type
, является не выводимым контекстом, и поэтому первый параметр функции не будет использоваться для вывода Args
, что, в свою очередь, означает, что будут рассматриваться неявные преобразования (например, преобразование лямбда-функции в указатель).
В качестве альтернативы, как упомянуто @ FrançoisAndrieux в комментариях к вопросу, вы можете использовать трюк lambda +
для преобразования лямбда-выражения в указатель функции на сайте вызова:
do_test(+[](int &y) { y++; }, x);
Также обратите внимание, что берется указатель на функцию указанного типа c означает, что функция может быть вызвана только с функциями, которые имеют точно этого типа. Например, args
всегда выводится для ссылочного типа, поэтому любая возможная функция, которая может использоваться с этой, должна принимать только ссылочные параметры. Обычно это не то, что вы хотите. Обычно вам нужно свободное поведение std::function<R(Args...)>
, которое может быть создано из любого функционального объекта, вызываемого с указанным Args
и возвращающего что-то, что может быть неявно преобразовано в R
.