Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic template function accepting lambda

I'm trying to understand the compiler error that I'm getting fo the code below. I've got a variadic template function which accepts a lambda with the specified types, and attempting to call that function results in the template not being considered a valid candidate due to a mismatch.

#include <functional>

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

int main(int argc, char **argv)
{
    executeWithResultHandler<int>([] (int arg) {
    });
    return 0;
}

This results in the following error:

$ c++ -std=c++11 reduction.cpp 
reduction.cpp:10:5: error: no matching function for call to 'executeWithResultHandler'
    executeWithResultHandler<int>([] (int arg) {
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reduction.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against
      '<lambda at reduction.cpp:10:35>'
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
     ^
1 error generated.

If I change the declaration to not be variadic:

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

then it works for the toy example above, but for the real problem I need arbitrary arguments. Is there something I’m missing here, or anther way to accomplish this?

EDIT: This was marked as a duplicate incorrectly, I believe- the dupe does not answer the question I'm asking. This question specifically has to do with the variadic template issue here: Please note that, when I switch the template to be non-variadic the lambda converts to the std::function type correctly, as expected. This is true regardless of the number of arguments, as long as that is not handled in a variadic fashion.

However, it does not work with the variadic version specifically, despite an expectation that the parameter pack is unpacked to a set of real parameters, and the explicit specification of the template parameter list at the function call site.

like image 705
kihlasht Avatar asked Jan 10 '23 05:01

kihlasht


1 Answers

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));
}
like image 151
Daniel Frey Avatar answered Jan 18 '23 08:01

Daniel Frey