【问题标题】:Why don't lambda expressions require <functional>, but function<void()> does?为什么 lambda 表达式不需要 <functional>,而 function<void()> 需要?
【发布时间】:2016-09-07 00:08:38
【问题描述】:

我有一些使用 lambda 表达式的代码:

#include <vector>
#include <algorithm>
int main(){
    std::vector<int> vi={3,1};
    std::sort(vi.begin(),vi.end(),[](int x,int y){
        return x<y;
    });
    return 0;
}

编译不需要#include&lt; functional&gt;,但是如果我使用变量来存储lambda函数:

#include <vector>
#include <algorithm>
#include <functional>
int main(){
    std::vector<int> vi={3,1};
    std::function<void()> compf=[](int x,int y){
        return x<y;
    };
    std::sort(vi.begin(),vi.end(),compf);
    return 0;
}

那我需要包含&lt;functional&gt; 来编译,为什么?为什么sort() 还没有包含&lt;functional&gt;?

【问题讨论】:

  • 您是否认为 lambda 是 std::function?它不是;当您将其存储到 compf 时,会涉及到转换。
  • 因为 lambda 表达式是语言的一部分。 std::function 是标准库的一部分,因此需要包含头文件。
  • @PaulRooney,公平地说,for (int i : {1, 2, 3}) 还需要包含标头,尽管没有明确使用标准库。
  • @chris true。我总觉得这有点奇怪。

标签: c++ lambda


【解决方案1】:

因为 lambda 表达式是编译器提供的核心语言功能。 std::function 是一个库功能,在代码中实现。请注意,您无需包含任何内容即可将 lambda 存储在变量中。

auto f = [](int x, int y){ return x < y; };

如果您打算将 &lt;functional&gt; 存储在 std::function 中,则只需包含它(因为它就是在其中实现的)。

您似乎认为 lambda 的类型是 std::function。它不是。每个 lambda 表达式都有自己独特的、不可命名的类型。我用auto 捕获了上面的那个类型。 std::function 是一种更通用的类型,可以存储 any 具有适当签名的类似函数的对象。例如,我可以创建一个std::function&lt;int(int,int)&gt; 对象,并为其分配一个普通函数、一个函数对象和一个 lambda。

#include <functional>
int minus_func(int a, int b) { return a - b; }

struct plus_t {
    int operator()(int a, int b) const { return a + b; }
};

int main() {
    auto mult_lambda = [](int a, int b) { return a * b; };

    std::function<int(int,int)> func;
    func = minus_func;
    func = plus_t{};
    func = mult_lambda;
}

这种通用性也有代价,以动态分配和间接的形式。而通过其实际类型的变量使用 lambda 通常是内联的。

【讨论】:

  • std::function&lt;&gt; 实现可能具有静态存储,以避免动态分配低于特定大小的可调用对象。这类似于小字符串优化。
  • 行 "func=plus_t{}" 应该如何工作?它会创建一个 "plus_t" 类型的匿名对象吗?
  • 您的意思是“分配给它”而不是“分配给它”吗?
  • @blackpen:是的,它就是这么做的。它使用统一的初始化语法。我也可以使用更传统的func = plus_t();。
  • @user2296177 对于某些对象(函数指针和其他一些),“必须”具有,对于对象(通常在一定大小以下),“可能”具有,但没有规定小型 lambda 必须永远与 SOO 一起存储在 std::function 中(但是,这是库实现的质量问题)。如果我没记错的话,一个流行的标准库(MSVC)将 SOO 任何不超过两个 std::strings 的可调用对象(它们本身有 SOO 用于短字符串)。
【解决方案2】:

lambda 函数是语言的一部分——独立于任何库。

另一方面,std::function 是标准库的一部分,在标准库头文件functional 中定义。

因此,使用

std::sort(vi.begin(),vi.end(),[](int x,int y){
    return x<y;
});

在使用时不要求functional 为#included

std::function<void()> compf=[](int x,int y){
    return x<y;
};
std::sort(vi.begin(),vi.end(),compf);

要求functional 为#included。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2018-07-30
    • 2011-06-18
    • 2021-04-13
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    相关资源
    最近更新 更多