Лямбда выводится в std :: function, если шаблон не имеет переменных аргументов - PullRequest
0 голосов
/ 17 октября 2018
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 ]

0 голосов
/ 17 октября 2018
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, то этобольше не будет автоматически выводить аргументы.

Обратите внимание, что вывод типа стирания типа a, такого как std::function, обычно является запахом кода.

Замените оба на:

template<class F>
void bar(F callback)
{}

если вам нужно получить аргументы, используйте помощники для функций (их много на SO).Если вам просто нужно возвращаемое значение, есть std черт, которые уже справляются с этим.


В вы можете сделать это:

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);
}

с использованием функции .

0 голосов
/ 17 октября 2018

У вас нет никаких вычетов для параметров типа bar, они полностью указаны.

У вас все еще есть хвост пакета, который нужно вывести в foo, и это не получается, потому что лямбда не является std::function.

...