繁体   English   中英

变体模板函数接受lambda

[英]Variadic template function accepting lambda

我试图理解我在下面的代码中得到的编译器错误。 我有一个可变参数模板函数,它接受一个具有指定类型的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;
}

这会导致以下错误:

$ 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.

如果我将声明更改为variadic:

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

然后它适用于上面的玩具示例,但对于真正的问题,我需要任意参数。 有没有我在这里缺少的东西,或者其他方法来实现这一目标?

编辑:这被标记为重复不正确,我相信 - 这个骗局没有回答我问的问题。 这个问题特别与这里的可变参数模板问题有关:请注意,当我将模板切换为非可变参数时,lambda正确地转换为std :: function类型,如预期的那样。 无论参数的数量是多少都是如此,只要不以可变方式处理。

但是,它没有特别适用于可变参数版本,尽管期望参数包被解包为一组实际参数,并且在函数调用站点显式指定模板参数列表。

在你的情况下,可变参数模板的问题是编译器不知道你明确指定的int是否是ResultTypes...完整列表ResultTypes...所以它试图从你给它的参数中推导出可选的剩余参数,并且这显然是失败的。 这是可变参数模板参数的常见缺陷,并不仅限于lambdas。

解决方案始终意味着您从编译器中删除此选项,例如

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

我之前将其作为重复链接的问题可以准确地解释您的情况。

std::function 不是 lambda,它是可以存储任何类型的可调用对象的容器类型。 您可以将lambda分配给std::function ,但在这种情况下,必需的转换由std::function构造std::function执行。

在你的例子中

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

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

编译器无法从上面的lambda表达式推断参数包ResultTypes的类型。 模板参数推导需要完全匹配,不考虑隐式转换,并且如前所述,此处涉及的类型完全不同。


如果我将声明更改为variadic,那么它可以工作

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

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

这是有效的,因为不再涉及模板参数推断。 executeWithResultHandler接受一个你明确指定的模板参数,并且因为lambda可以隐式转换为std::function ,所以重载解析会找到匹配项。

请注意,在第一种情况下,除了int之外,可能还有更多的模板参数,您没有明确指定。


您可以通过将lambda显式转换为std::function来获得原始示例。

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

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM