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.
Насколько я понимаю, вычет типа шаблона не учитывает преобразования типов. Так не должны ли оба терпеть неудачу?
Ответ 1
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
он больше не будет автоматически выводить аргументы.
Обратите внимание, что вывод типа типа стирания типа aa, такого как 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.
Ответ 2
У вас нет вычетов для параметров типа bar
, они полностью указаны.
У вас все еще есть хвост пакета для вывода в foo
, и это терпит неудачу, потому что лямбда не является std::function
.