用C++转发lambda的声明

MxN*_*xNx 34 c++ lambda declaration definition c++11

在C++中,可以分离函数的声明和定义.例如,声明一个函数是很正常的:

int Foo(int x);
Run Code Online (Sandbox Code Playgroud)

Foo.h贯彻它Foo.cpp.是否有可能与lambdas做类似的事情?例如,定义一个

std::function<int(int)> bar;
Run Code Online (Sandbox Code Playgroud)

在以下内容中bar.h实现它bar.cpp:

std::function<int(int)> bar = [](int n)
{
    if (n >= 5) 
        return n;
    return n*(n + 1);
};
Run Code Online (Sandbox Code Playgroud)

免责声明:我在C#中有使用lambdas的经验,但我没有在C++中使用过它们.

son*_*yao 40

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

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

// bar.h
extern std::function<int(int)> bar;     // declaration
Run Code Online (Sandbox Code Playgroud)

// bar.cpp
std::function<int(int)> bar = [](int n) // definition
{
    if (n >= 5) return n;
    return n*(n + 1);
};
Run Code Online (Sandbox Code Playgroud)

再次注意,这不是lambda的单独声明和定义; 它只是单独声明和定义bar带有类型的全局变量std::function<int(int)>,它是从lambda表达式初始化的.

  • 代码示例非常具有说明性. (2认同)

bas*_*hrc 8

严格来说,你不能

引用cpp引用

lambda表达式是一个prvalue表达式,其值为(直到C++ 17),其结果对象是(从C++ 17开始)一个未命名的非联合非聚合类类型的临时对象,称为闭包类型,在包含lambda表达式的最小块作用域,类作用域或命名空间作用域中声明(出于ADL的目的)

所以lambda是一个未命名的临时对象.您可以将lambda绑定到l值对象(例如std::function),并通过有关变量声明的常规规则,您可以将声明和定义分开.


650*_*502 8

前向声明不是正确的术语,因为C++中的lambda是对象,而不是函数.代码:

std::function<int(int)> bar;
Run Code Online (Sandbox Code Playgroud)

声明一个变量,你不必强制分配它(该类型的默认值为"指向无函数的指针").你甚至可以编译它的调用...例如代码:

#include <functional>
#include <iostream>

int main(int argc, const char *argv[]) {
    std::function<int(int)> bar;
    std::cout << bar(21) << "\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

将干净地编译(但当然会在运行时疯狂地表现).

也就是说,您可以将lambda分配给兼容std::function变量并添加例如:

bar = [](int x){ return x*2; };
Run Code Online (Sandbox Code Playgroud)

在调用之前将导致编译良好的程序并生成输出42.

关于C++中lambda的一些非显而易见的事情(如果你知道其他有这个概念的语言)是那个

  • [..](...){...}即使签名完全相同,每个lambda 也有不同的不兼容类型.例如,你不能声明lambda类型的参数,因为唯一的方法是使用类似的东西,decltype([] ...)但是没有办法调用函数,因为[]...调用站点上的任何其他形式都是不兼容的.std::function如果你必须传递lambdas或将它们存储在你必须使用的容器中,这就解决了std::function.

  • Lambda可以按值捕获本地(但它们const除非你声明lambda mutable)或通过引用(但保证引用对象的生命周期不会短于lambda的生命周期由程序员决定).C++没有垃圾收集器,这是正确解决"向上funarg"问题所需的东西(你可以通过捕获智能指针来解决,但你必须注意引用循环以避免泄漏).

  • 与其他语言不同,lambdas可以被复制,当你复制它们时,你正在拍摄它们内部捕获的按值变量的快照.对于可变状态,这可能是非常令人惊讶的,这是我认为const默认情况下捕获的值 - 值的原因.

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

std::function<int(int)> timesK(int k) {
    return [k](int x){ return x*k; };
}
Run Code Online (Sandbox Code Playgroud)

基本上就像

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

有一个微妙的区别,甚至可以复制lambda捕获引用(通常包含引用的类作为成员不能).