Lou*_*tra 5 c++ lambda compilation language-lawyer
我想知道编译器如何处理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)
Run Code Online (Sandbox Code Playgroud)
虽然,引起我的注意的是,它确实编译了传递constexpr lambda,但是没有编译通过constexpr常规(全局)函数.是什么导致这种差异?编译器在常规函数和lambda函数之间是否存在其他行为差异?
编辑:Lambda实现的示例
foo([](){ return 4; }); // C++17 Lambda's are implicitly constexpr
Run Code Online (Sandbox Code Playgroud)
在这种情况下,lambda基本上是值的包装器.
编辑:全局功能
每当传递一个全局函数时,编译器会抱怨 - 而不是使用lambda - 该函数,无论是否定义为constexpr,都不能在常量条件下使用:
prog.cc:8:20: error: 'l' is not a constant expression
Run Code Online (Sandbox Code Playgroud)
从您的代码片段中删除一些无关的内容,我们得到
template<typename T>
constexpr void foo(T t)
{
constexpr int i = t();
}
constexpr int f() { return 42; }
auto l = []{ return 42; }
Run Code Online (Sandbox Code Playgroud)
评论:
您正在尝试用作t()inside constexpr。事实上可能是一个正常的功能并且仍然表现相同。foofoo
lambda不是函数。它是一个带有operator().
struct L { constexpr int operator()() const { return 42; } };
Run Code Online (Sandbox Code Playgroud)
TL被推导为与调用中等效的类型foo(l)。
Tint(*)()与调用中一样推导出来foo(f)。
在这两种情况下,t 都不是中的 constexpr foo。
表达式
e是核心常量表达式e,除非 的求值遵循抽象机的规则,将求值以下表达式之一:[...]
左值到右值的转换,除非 [...]
一个非易失性泛左值,它引用用 constexpr 定义的非易失性对象,或者引用此类对象的非可变子对象,或者
文字类型的非易失性泛左值,引用其生命周期开始于 的求值内的非易失性对象
e;
通过 a 调用int(*)()需要进行左值到右值的转换。t不是用 定义的对象constexpr,它的生命周期也不是在 的求值中开始的t()。因此t()不是constexprin foo(f)。
调用operator()不需要左值到右值的转换。由于没有成员访问,因此它只是一个constexpr函数调用。因此t()是 aconstexpr在foo(l).
从核心常量表达式到常量表达式还多了一步,但对于这里的讨论来说并不重要。