Лямбда выводится в std::function, если шаблон не имеет переменных аргументов
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
template<typename ReturnT, typename ParamT>
void bar(std::function<ReturnT(ParamT)> callback)
{}
main()
{
foo<int, int>([](int x){ return x; }); // no instance of function
// template matches argument list
bar<int, int>([](int x){ return x; }); // OK
}
Единственная разница между foo и bar в том, что у foo есть аргументы с переменным числом аргументов. Каким-то образом компилятор может преобразовать лямбду в std::function в bar.
Насколько я понимаю, вычитание типа шаблона не учитывает преобразования типов. Так не должны ли оба потерпеть неудачу?
2 ответа
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
сейчас, foo<int,int>
является foo<ReturnT=int, ParamsT starts with {int}>
,
Это не полностью указывает ParamT
, На самом деле, нет возможности полностью указать ParamT
,
Как не полностью указанный шаблон, происходит удержание и происходит сбой. Он не пытается "что делать, если я просто предполагаю, что пакет не идет дальше".
Вы можете исправить это с помощью:
template<typename ReturnT, typename... ParamT>
void foo(block_deduction<std::function<ReturnT(ParamT...)>> callback)
{}
где block_deduction
похоже:
template<class T>
struct block_deduction_helper { using type=T; }:
template<class T>
using block_deduction = typename block_deduction_helper<T>::type;
теперь вычет заблокирован на foo
Первый аргумент
И твой код работает.
Конечно, если вы проходите в std::function
он больше не будет автоматически выводить аргументы.
Обратите внимание, что вывод типа типа стирания типа std::function
обычно это кодовый запах.
Заменить оба на:
template<class F>
void bar(F callback)
{}
если вам нужно получить аргументы, используйте хелперы свойств функций (их много на SO). Если вам просто нужно вернуть значение, есть std
черты, которые уже решают это.
В C++17 вы можете сделать это:
tempate<class R, class...Args>
void bar( std::function<R(Args...)> f ) {}
template<class F>
void bar( F f ) {
std::function std_f = std::move(f);
bar(std_f);
}
с помощью функции руководств дедукции C++17.
У вас нет каких-либо вычетов для параметров типа bar
, они полностью указаны.
У вас все еще есть хвост пакета, чтобы вывести в foo
и это терпит неудачу, потому что лямбда не std::function
,