【问题标题】:Call a function with std::function as argument with a lambda使用 std::function 作为 lambda 参数调用函数
【发布时间】:2019-08-29 17:06:23
【问题描述】:

我从这里得到的问题的基础: Failure to deduce template argument std::function from lambda function 这个线程中的问题是: 为什么这段代码不能将 lambda 传递给函数:

#include <iostream>
#include <functional>

template <typename T>
void call(std::function<void(T)> f, T v)
{
    f(v);
}

int main(int argc, char const *argv[])
{
    auto foo = [](int i) {
        std::cout << i << std::endl;
    };
    call(foo, 1);
    return 0;
}

这个帖子的答案是,因为 lambda 不是 std::function。但是为什么要编译这段代码:

#include <iostream>
#include <functional>

template <typename T>
void call(std::function<void(T)> f, T v)
{
    f(v);
}

int main(int argc, char const *argv[])
{
    auto foo = [](int i) {
        std::cout << i << std::endl;
    };
    call({foo}, 1); // changed foo to {foo}
    return 0;
}

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    如链接答案中所写,第一个版本无法编译,因为第一个参数的模板参数推导失败; lambda 永远不是std::function&lt;void(T)&gt;

    第二个版本可以编译,因为通过编写{foo}std::function&lt;void(T)&gt; 变成了一个非推导上下文。因此,第一个论点的演绎不会再失败,因为它甚至没有尝试过。所以 T 仅从第二个参数推导出为 int,并且调用成功,因为 lambda 可以转换为 std::function&lt;void(int)&gt;

    来自[temp.deduct.type]:

    未推断的上下文是:

    • ...
    • 一个函数参数,其关联参数是一个初始化列表,但参数 没有指定从初始值设定项列表中扣除的类型。

    【讨论】:

    • 所以使用 lambda 调用 template &lt;typename T&gt; call(std::function&lt;void(T)&gt; f) 会失败,对吧?
    • 如果std::function 有一个以std::initializer_list 为参数的构造函数,它会失败吗?
    • 不,这里没关系。仅当参数本身是初始值设定项列表或数组时,才会从初始值设定项列表参数中进行推导。例如:template &lt;typename T&gt; max(std::initializer_list&lt;T&gt; values)可以从max({1, 2, 3})推导出T = int
    • 好人,所以template &lt;typename T&gt; void call(decltype(std::function&lt;void(T)&gt;{}) f, T v)call([](int a) {}, 1) 应该也可以工作。我现在觉得我重新发现了轮子。这么多年C++,然后这个。谢谢:)
    • 是的。此外,未来标准批准的引入非推断上下文的方法是使用std::type_identity
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    相关资源
    最近更新 更多