C++11:将lambda转换为源代码中的函数对象

C++11: convert lambdas to function-objects in source

本文关键字:函数 对象 源代码 lambda 转换 C++11      更新时间:2023-10-16

我有一个C++11代码库,需要在不支持lambdas的旧编译器上构建。手动将所有Lambda更改为手工制作的函数对象是不现实的。

有人知道我可以作为预编译步骤运行的工具吗?它会自动将所有lambda提取到它们的等效函数类中?我在想我是否可以使用clang的前端。

有人知道我可以作为预编译步骤运行的工具吗?它会自动将所有lambda提取到它们的等效函数类中?

好吧,这样的工具理论上可能存在,但即使确实存在,首先简单地切换到较新的编译器也会更实用。

让我们考虑以下代码:

template <class F>
auto apply_0(F f) -> decltype(f(0)) {
    auto g = [f] (int x) { return f(x); };
    return g(0);
}

在这种情况下,我们的工具需要生成返回auto类型的函数对象(这意味着,生成的代码需要使用C++14进行编译),或者实例化模板来检测代码中出现的所有可能的返回类型(此时切换到C++14会更容易)。

但是,让我们考虑最乐观的情况:整个项目中的所有lambda表达式都使用->定义其返回类型,并且它们不会出现在模板函数中——在这种情况下,理论上您可以使用operator()和构造函数将lambda表达式转换为等效的结构,该结构将变量捕获为结构成员——它会为您提供相同行为的代码吗?答案是:它是由实现定义的

考虑尽可能小的lambda:

auto f = [] { return 0; };
cout << is_pod<decltype(f)>::value << endl;

使用g++编译时,此代码将写入"0",使用clang++编译时将写入"1"。如果我们将这个lambda转换为函数对象,那么得到的结构在gcc和clang中都将是POD类型。另一个例子:

int x = 42;
auto f = [x] { return x; };
cout << is_pod<decltype(f)>::value << endl;

g++仍将给出"0",clang++仍将提供"1"。在转换为结构的过程中,我们需要为函数对象的绑定成员x编写一些初始值设定项(构造函数或其他)-根据实现的不同,它可能是POD或非POD-这可能与编译器在为lambda创建匿名闭包对象时所做的不同。

C++11标准§5.1.2.3:列出了其他可能发生变化的内容

一个实现可以定义不同于下面描述的闭包类型,前提是这不会改变程序而不是通过更改:

  • 闭合类型的尺寸和/或对准
  • 闭包类型是否是一般可复制的(第9条)
  • 闭合类型是否为标准布局类别(第9条),或
  • 闭包类型是否是POD类(第9条)

和往常一样,你的代码不应该依赖于语言的实现定义部分——所以这不是什么大不了的事,但它可能会导致意想不到的后果。

据我所知,还没有构建这样的工具,但如果你想实现一个,你最好的基础设施选择是Clang和ROSE。