Лямбда выводится в 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,

Другие вопросы по тегам