接受 lambda 的可变参数模板函数

kih*_*sht 4 c++ lambda templates variadic-templates c++11

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

这会导致以下错误:

$ 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.
Run Code Online (Sandbox Code Playgroud)

如果我将声明更改为非可变参数:

template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
Run Code Online (Sandbox Code Playgroud)

那么它适用于上面的玩具示例,但对于真正的问题,我需要任意参数。我在这里遗漏了什么,或者用另一种方式来完成这个?

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

但是,它并没有使用专门的可变参数版本,尽管工作的期望,参数包解压后是一组真实参数,并在模板参数列表中的函数调用网站的明确规范。

Dan*_*rey 5

在您的情况下,可变参数模板的问题在于编译器不知道int您明确指定的是否是完整列表ResultTypes...,因此它试图从您提供的参数中推断出可选的剩余参数,这显然失败了。这是可变参数模板参数的常见陷阱,它不仅限于 lambda。

解决方案总是暗示您从编译器中删除此选项,例如

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));
}
Run Code Online (Sandbox Code Playgroud)