编译器如何对待lambda与常规函数不同?

劳伦斯·迪克斯特拉(Lourens Dijkstra)

我想知道编译器如何对待lambda函数而不是常规函数。甚至不包括捕获列表,正如我认为的那样,它的行为似乎也略有不同。

例如,在我的上一篇文章中,尝试传递constexpr lambda并使用它来显式指定返回类型,我使用了constexpr lambda并将其作为常规函数参数传递。我引用了部分答案。

constexpr函数的参数本身不是constexpr对象-因此,不能在常量表达式中使用它们。

template <typename Lambda_T>
constexpr static auto foo(Lambda_T l) {
    return std::array<event, (l())>{};
} 
// Compiles with GCC (C++17), though ill-formed (according to the answer of my last post)

不过,引起我注意的是,这确实通过传递编译constexpr lambda,但没有通过constexpr常规(全局)函数进行编译。是什么原因导致这种差异?常规函数和lambda函数之间的编译器行为是否还有其他区别?

编辑:Lambda实现的示例

foo([](){ return 4; }); // C++17 Lambda's are implicitly constexpr

在这种情况下,lambda基本上是该值的包装器。

编辑:全局功能

每当传递全局函数时,与使用lambda相对,编译器都会抱怨该函数(无论是否定义为constexpr)都不能在恒定条件下使用:

prog.cc:8:20: error: 'l' is not a constant expression
适合者

从您的代码段中删除一些多余的内容,我们得到

template<typename T>
constexpr void foo(T t)
{
    constexpr int i = t();
}

constexpr int f() { return 42; }
auto l = []{ return 42; }

备注:

  1. 您正在尝试使用t()constexpr范围内foofoo实际上可以是正常功能,但仍然表现相同。

  2. Lambda不是函数。它是带有的匿名结构operator()

    struct L { constexpr int operator()() const { return 42; } };
    

    T被推导为L与call中等效的类型foo(l)

  3. Tint(*)()通话一样推论foo(f)

  4. 在这两种情况下,t 都不是中的constexpr foo


来自[expr.const]

表达式e是核心常量表达式,除非按照e抽象机的规则进行的求值将对以下表达式之一求值:[...]

  • 左值到右值的转换,除非[...]

    • 非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用该对象的非可变子对象,或者

    • 文字类型的非易失性glvalue,指的是其寿命在的求值内开始的非易失性对象e

通过调用int(*)()需要从左值到右值的转换。t不是定义的对象constexpr,它也不在的评估中开始生命周期t()因此t()不是constexprin foo(f)

调用operator()不需要从左值到右值的转换。由于没有成员访问权限,因此它只是一个constexpr函数调用。因此t()是一个constexprfoo(l)

从核心常量表达式到常量表达式还有一个步骤,但是对于此处的讨论并不重要。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么这两个条件被编译器以不同方式对待?

为什么G ++编译器不以相同的方式对待这两个函数?

了解编译器如何解析函数指针

编译器如何选择正确的重载函数?

通用Lambda上的编译器崩溃

如果constexpr在递归通用lambda中:编译器行为不同

如果constexpr位于lambda中,则编译器行为不同

编译器是否为每个lambda生成不同的类型?

TypeScript编译器:如何从CallExpression获取原始函数的FunctionDeclaration?

编译器如何解释函数调用中的冒号?

编译器如何快速评估constexpr函数?

编译器给出lambda函数强制转换错误

编译器说,公共常规方法必须是公共的

C ++编译器如何检测非常量函数体?

为何编译器以不同的方式对待这两条等效(?)行?

如果不使用返回值,g ++编译器是否将constexpr函数视为常规函数?

编译器如何区分std :: vector的构造函数?

编译器如何快速评估递归constexpr函数?

取决于编译器的不同构造函数调用

如何使编译器比Swift常规函数更喜欢我的函数?

编译器如何确定要调用的函数模板?

C ++编译器如何有效地内嵌函数局部的lambda?

如何检查内联函数是否已由编译器自动转换为常规函数?

如何安装两个不同的编译器?

Java中只允许在代码中保留分号。幕后发生了什么?编译器和JVM如何对待它们?

strftime()函数显示系统编译器和在线编译器中的不同行为

在不同的编译器中的程序集上定义函数

如何让编译器处理这个函数?

如何帮助编译器优化 lambda 调用?