Variadic template function accepting lambda

隐身守侯 提交于 2019-12-04 11:59:59

The problem with variadic templates in your case is that the compiler does not know whether the int you explicitly specified is the complete list for ResultTypes... or not, so it tries to deduce the optional remaining arguments from the parameter you gave it, and that obviously fails. This is a common pitfall with variadic template arguments and it is not limited to lambdas.

A solution always implies that you take away this option from the compiler, e.g.

template<typename ... ResultTypes>
void executeWithResultHandler_impl(std::function<void (ResultTypes...)> lambda)
{
}

template<typename ... ResultTypes, typename F>
void executeWithResultHandler(F&& lambda)
{
    executeWithResultHandler_impl(std::function<void (ResultTypes...)>(lambda));
}
Praetorian

The question I'd previously linked as duplicate explains exactly what is going in your case.

An std::function is not a lambda, it is type of container that can store any kind of callable object. You can assign a lambda to an std::function, but in that case the necessary conversion is performed by the std::function constructor.

In your example

template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{}

executeWithResultHandler<int>([](int arg){});

the compiler has no way of inferring the types in the parameter pack ResultTypes from the lambda expression above. Template argument deduction requires exact matches, implicit conversions are not considered, and the types involved here, as mentioned earlier, are completely different.


If I change the declaration to not be variadic then it works

template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{}

 executeWithResultHandler<int>([](int arg){});

This works because there's no template argument deduction involved anymore. executeWithResultHandler takes exactly one template parameter, which you've explicitly specified, and because a lambda is implicitly convertible to std::function, overload resolution will find a match.

Note that in the first case there may have been more template arguments, in addition to int, that you hadn't specified explicitly.


You can get your original example to work by explicitly converting the lambda to std::function.

executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!