用C ++转发lambda的声明

时间:2016-11-22 06:26:40

标签: c++ c++11 lambda declaration definition

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

int Foo(int x);
<{1>}中的

并在Foo.h中实施。是否有可能与lambdas做类似的事情?例如,定义一个

Foo.cpp
std::function<int(int)> bar;

并在bar.h中将其实现为:

bar.cpp

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

3 个答案:

答案 0 :(得分:39)

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

如您所示的示例代码一直在使用std::function,请注意本案例bar确实是一个全局变量,您需要在头文件中使用extern来制作它是一个声明(不是定义)。

// bar.h
extern std::function<int(int)> bar;     // declaration

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

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

答案 1 :(得分:8)

严格来说,你不能

引自cpp reference

  

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

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

答案 2 :(得分:6)

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

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

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

#include <functional>
#include <iostream>

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

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

那就是说你可以将lambda分配给兼容的std::function变量并添加例如:

bar = [](int x){ return x*2; };
在调用之前

将导致编译良好的程序并生成输出42。

一些非常明显的事情可能会令人惊讶,因为C ++中的lambdas(如果你知道其他有这个概念的语言)就是那个

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

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

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

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

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);
}

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