简体   繁体   English

变体模板函数接受lambda

[英]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. 我有一个可变参数模板函数,它接受一个具有指定类型的lambda,并且尝试调用该函数会导致模板由于不匹配而不被视为有效候选。

#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: 如果我将声明更改为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. 这个问题特别与这里的可变参数模板问题有关:请注意,当我将模板切换为非可变参数时,lambda正确地转换为std :: function类型,如预期的那样。 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. 但是,它没有特别适用于可变参数版本,尽管期望参数包被解包为一组实际参数,并且在函数调用站点显式指定模板参数列表。

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. 在你的情况下,可变参数模板的问题是编译器不知道你明确指定的int是否是ResultTypes...完整列表ResultTypes...所以它试图从你给它的参数中推导出可选的剩余参数,并且这显然是失败的。 This is a common pitfall with variadic template arguments and it is not limited to lambdas. 这是可变参数模板参数的常见缺陷,并不仅限于lambdas。

A solution always implies that you take away this option from the compiler, eg 解决方案始终意味着您从编译器中删除此选项,例如

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

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. std::function 不是 lambda,它是可以存储任何类型的可调用对象的容器类型。 You can assign a lambda to an std::function , but in that case the necessary conversion is performed by the std::function constructor. 您可以将lambda分配给std::function ,但在这种情况下,必需的转换由std::function构造std::function执行。

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. 编译器无法从上面的lambda表达式推断参数包ResultTypes的类型。 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 如果我将声明更改为variadic,那么它可以工作

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. executeWithResultHandler接受一个你明确指定的模板参数,并且因为lambda可以隐式转换为std::function ,所以重载解析会找到匹配项。

Note that in the first case there may have been more template arguments, in addition to int , that you hadn't specified explicitly. 请注意,在第一种情况下,除了int之外,可能还有更多的模板参数,您没有明确指定。


You can get your original example to work by explicitly converting the lambda to std::function . 您可以通过将lambda显式转换为std::function来获得原始示例。

executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 接受可变参数 lambda 时 std::function 的签名 - Signature of std::function when accepting a variadic lambda 将std :: function与lambda和variadic模板一起使用 - Use std::function with lambda and variadic template 是否可以从函数模板返回可变参数lambda? - Is it possible to return a variadic lambda from a function template? Variadic lambda vs variadic template function:严格等效? - Variadic lambda vs variadic template function : stricly equivalent? 使用可变参数lambda迭代可变参数函数模板的参数 - Iterating through parameters of a variadic function template using variadic lambda 接受嵌套的可变参数类模板作为函数模板的参数 - Accepting nested variadic class templates as arguments to function template 在variadic模板中从lambda隐式转换为std :: function - implicit convert from lambda to std::function inside variadic template 可变参数模板函数是否以相反顺序调用lambda参数? - Does variadic template function call lambda parameter in reverse order? 如何在可变参数模板类中将lambda表达作为参数传递给mermber函数 - how to pass lambda express as parameter into mermber function in variadic template class 如果模板没有可变参数,则将Lambda推导为std :: function - Lambda is deduced to std::function if template has no variadic arguments
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM