我想知道编译器如何对待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; }
备注:
您正在尝试使用t()
的constexpr
范围内foo
。foo
实际上可以是正常功能,但仍然表现相同。
Lambda不是函数。它是带有的匿名结构operator()
。
struct L { constexpr int operator()() const { return 42; } };
T
被推导为L
与call中等效的类型foo(l)
。
T
像int(*)()
通话一样推论foo(f)
。
在这两种情况下,t
都不是中的constexpr foo
。
表达式
e
是核心常量表达式,除非按照e
抽象机的规则进行的求值将对以下表达式之一求值:[...]
左值到右值的转换,除非[...]
非易失性glvalue,它引用用constexpr定义的非易失性对象,或引用该对象的非可变子对象,或者
文字类型的非易失性glvalue,指的是其寿命在的求值内开始的非易失性对象
e
。
通过调用int(*)()
需要从左值到右值的转换。t
不是定义的对象constexpr
,它也不在的评估中开始生命周期t()
。因此t()
不是constexpr
in foo(f)
。
调用operator()
不需要从左值到右值的转换。由于没有成员访问权限,因此它只是一个constexpr
函数调用。因此t()
是一个constexpr
在foo(l)
。
从核心常量表达式到常量表达式还有一个步骤,但是对于此处的讨论并不重要。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句