C+中lambdas的远期申报+; 在C++中,可以分离函数的声明和定义。例如,声明函数是很正常的: int Foo(int x);

C+中lambdas的远期申报+; 在C++中,可以分离函数的声明和定义。例如,声明函数是很正常的: int Foo(int x);,c++,c++11,lambda,declaration,definition,C++,C++11,Lambda,Declaration,Definition,在Foo.h中,并在Foo.cpp中实现它。有可能对lambdas做类似的事情吗?例如,定义一个 std::function<int(int)> bar; 免责声明< /强>:我在C语言中有过lambda的经验,但我在C++中没有使用过。不能分开声明和定义,也不能向前声明。它的类型是一个使用lambda表达式声明的唯一未命名闭包类型。但您可以使用对象来实现这一点,对象被设计为能够存储任何可调用的目标,包括lambda 正如示例代码所示,您一直在使用std::function,请注

Foo.h
中,并在
Foo.cpp
中实现它。有可能对lambdas做类似的事情吗?例如,定义一个

std::function<int(int)> bar;

<强>免责声明< /强>:我在C语言中有过lambda的经验,但我在C++中没有使用过。

不能分开声明和定义,也不能向前声明。它的类型是一个使用lambda表达式声明的唯一未命名闭包类型。但您可以使用对象来实现这一点,对象被设计为能够存储任何可调用的目标,包括lambda

正如示例代码所示,您一直在使用
std::function
,请注意,对于这种情况,
bar
实际上是一个全局变量,您需要在头文件中使用
extern
,使其成为一个声明(而不是定义)

//bar.h
外部标准::功能栏;//宣言

//bar.cpp
std::功能条=[](int n)//定义
{
如果(n>=5)返回n;
返回n*(n+1);
};

再次注意,这不是lambda的单独声明和定义;它只是一个全局变量
bar
的单独声明和定义,类型为
std::function
,它是从lambda表达式初始化的。

严格来说,您不能

引用

lambda表达式是一个prvalue表达式,其值为(直到 C++17),其结果对象是(自C++17以来)未命名的临时对象 唯一的未命名非并集非聚合类类型,称为闭包 类型,以最小的 包含lambda的块范围、类范围或命名空间范围 表情


因此lambda是一个未命名的临时对象。您可以将lambda绑定到一个L值对象(例如,<>代码> STD::Fux< /Cl>),并且通过变量声明的规则,可以将声明和定义分开。

向前声明不是正确的术语,因为C++中的lambda是对象,不是函数。守则:

// bar.h
extern std::function<int(int)> bar;     // declaration
std::function<int(int)> bar;
在调用之前,将生成一个编译良好并生成输出42的程序

<>一些关于C++中的lambda的不明显的事情(如果你知道其他语言有这个概念)是

  • 每个lambda
    […](…){…}
    具有不同的不兼容类型,即使签名完全相同。例如,您不能声明lambda类型的参数,因为唯一的方法是使用类似于
    decltype([])
    的内容,但这样就无法调用该函数,因为调用站点上的任何其他
    []…
    表单都是不兼容的。这是通过
    std::function
    解决的,因此,如果必须传递lambda或将其存储在容器中,则必须使用
    std::function

  • lambda可以通过值捕获局部变量(但是它们是常量,除非声明lambda
    可变的),或者通过引用捕获局部变量(但是保证被引用对象的生存期不会短于lambda的生存期取决于程序员)。C++没有垃圾回收器,这是需要正确解决“向上的FunARG”问题(可以通过捕获智能指针来解决问题的方法,但是必须注意引用循环以避免泄漏)。
    
  • 与其他语言不同的是,lambda可以被复制,当你复制它们时,你可以通过值变量获取它们内部的快照。这对于可变状态来说是非常令人惊讶的,我认为这就是为什么默认情况下,值捕获的值是
    const

合理化和记住lambdas的许多细节的一种方法是如下代码:

std::function<int(int)> timesK(int k) {
    return [k](int x){ return x*k; };
}
std::函数timesK(int k){
返回[k](int x){return x*k;};
}
基本上就像

std::function<int(int)> timesK(int k) {
    struct __Lambda6502 {
        int k;
        __Lambda6502(int k) : k(k) {}
        int operator()(int x) {
            return x * k;
        }
    };
    return __Lambda6502(k);
}
std::函数timesK(int k){
结构Lambda6502{
int k;
__Lambda6502(int k):k(k){}
int运算符()(int x){
返回x*k;
}
};
返回值uu Lambda6502(k);
}

一个细微的区别是,即使lambda捕获引用也可以被复制(通常类包含引用,而成员则不能)。

如果要给lambda命名,最好将其作为一个普通函数。@Brian我知道,这很有意义。我问这个问题的主要原因是好奇,我想知道它的可能性<代码>标准::函数
能够存储lambda;但是lambda没有类型
std::function
;而是有自己独特的未命名类型。如果推导了变量的类型(通过
auto
或模板参数类型推导),则可以将lambda直接存储在变量中
std::function
有一个模板构造函数,它能够通过模板参数类型推断的原理获取lambda参数;b=13;您可以声明名称,而不是文字。你将如何申报13,为什么?你的lambda像13,
bar
b
。顺便说一句,C中的区别是一样的。您似乎混淆了(C#)委托和(C#)lambdas(本质上是:“匿名委托实现”)。在C++中,lambdas可以被分配给委托(变量),但它们不是一样的东西,就像C++一样。谢谢详细的响应。我可以问一下你们报价的来源吗?是从C++规范吗?@ MZHR注意到lambda的类型不是STD::For,而是一个未命名的LAMBDA类型。函数是围绕任何可调用对象的多态包装器。
#include <functional>
#include <iostream>

int main(int argc, const char *argv[]) {
    std::function<int(int)> bar;
    std::cout << bar(21) << "\n";
    return 0;
}
bar = [](int x){ return x*2; };
std::function<int(int)> timesK(int k) {
    return [k](int x){ return x*k; };
}
std::function<int(int)> timesK(int k) {
    struct __Lambda6502 {
        int k;
        __Lambda6502(int k) : k(k) {}
        int operator()(int x) {
            return x * k;
        }
    };
    return __Lambda6502(k);
}