C++ 编译器如何区别于常规函数处理lambda?
我想知道编译器是如何对待lambda函数而不是常规函数的。即使排除捕获列表,我认为它的名称,它的行为似乎略有不同 例如,正如我在上一篇文章中所使用的,我使用了一个constexpr lambda并将其作为常规函数参数传递。我引用了部分答案 constexpr函数的参数本身不是constexpr对象,因此不能在常量表达式中使用它们 在本例中,lambda基本上是值的包装器 编辑:全局功能C++ 编译器如何区别于常规函数处理lambda?,c++,lambda,compilation,language-lawyer,C++,Lambda,Compilation,Language Lawyer,我想知道编译器是如何对待lambda函数而不是常规函数的。即使排除捕获列表,我认为它的名称,它的行为似乎略有不同 例如,正如我在上一篇文章中所使用的,我使用了一个constexpr lambda并将其作为常规函数参数传递。我引用了部分答案 constexpr函数的参数本身不是constexpr对象,因此不能在常量表达式中使用它们 在本例中,lambda基本上是值的包装器 编辑:全局功能 foo([](){ return 4; }); // C++17 Lambda's are implicitl
foo([](){ return 4; }); // C++17 Lambda's are implicitly constexpr
无论何时传递全局函数,编译器都会抱怨(与使用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
被推断为调用foo(L)
中与L
等价的类型
T
在调用foo(f)
中被推断为int(*)(
)t
不是foo
中的constexpr从 表达式
e
是一个核心常量表达式,除非按照抽象机器的规则对e
的求值将求值以下表达式之一:[……]
- 左值到右值的转换,除非[…]
- 非易失性glvalue,指的是使用constexpr定义的非易失性对象,或指的是此类对象的不可变子对象,或
- 一种文本类型的非易失性glvalue值,指的是一个非易失性对象,其生存期开始于
的计算范围内e
int(*)(
调用需要左值到右值的转换t
不是用constexpr
定义的对象,也不是在t()
的计算中开始其生命周期的。因此t()
不是foo(f)
中的constepr
调用操作符()
不需要左值到右值的转换。由于没有成员访问权限,因此它只是一个constexpr
函数调用。因此t()
是foo(l)
中的constepr
从核心常量表达式到常量表达式有不同的定义,但在这里的讨论中并不重要。您可以展示lambda实现吗?如果您传递任何由常量表达式初始化的函子,它将编译。如果将
l()
替换为fptr()
,其中fptr
是由常量表达式初始化的函数指针,则它也将编译。我看到的唯一区别是,当使用函数参数调用时,应用于参数以初始化参数的函数到指针转换可能不会被假定为常量表达式。但我怀疑在c++20中,它应该被假定为一个恒定的初始化,而在c++17中,它甚至更加模糊。@Oliv Oops,我只是觉得你在我写答案时已经说过同样的话。
template<typename T>
constexpr void foo(T t)
{
constexpr int i = t();
}
constexpr int f() { return 42; }
auto l = []{ return 42; }
struct L { constexpr int operator()() const { return 42; } };