标准是否保证无捕获的lambda为空?


12

我正在寻找一种从模板函数中的其他lambda识别空(无捕获)lambda的方法。我目前正在使用C ++ 17,但我也对C ++ 20的答案感到好奇。

我的代码如下所示:

template<typename T>
auto func(T lambda) {
    // The aguments of the lambdas are unknown

    if constexpr (/* is captureless */) {
        // do stuff
    }
}

C ++标准(17或20)是否保证可转换为函数指针的不可捕获lambda也会使std::is_emptyyield 变为true?

以以下代码为例:

auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures

static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?

现场例子


2
如果只关心非模板lambda,则可以使用SFINAE来检查到函数指针(+lambda)的转换是否格式正确。
HolyBlackCat

@HolyBlackCat我曾考虑过这一点,但据我所记得,MSVC不允许这样做,因为它们使转换运算符重载了。
Guillaume Racicot

@GuillaumeRacicot MS为所有可用的调用约定公开了单独的转换运算符。只需选择一个并尝试将lambda转换为可比较的函数指针,然后检查它是否成功。
雷米·勒博

+似乎在这里工作。
HolyBlackCat

Answers:


13

不,事实上,该标准明确授予了lambda大小与其声明不一致的权限。 [expr.prim.lambda.closure] / 2个状态

在包含相应的lambda-expression的最小块范围,类范围或名称空间范围中声明闭包类型。[注意:这确定与闭包类型([basic.lookup.argdep])关联的名称空间和类的集合。lambda声明符的参数类型不会影响这些关联的名称空间和类。—结束说明]闭包类型不是聚合类型。一个实现可以定义与以下描述不同的闭包类型,但前提是这不会改变程序的可观察行为,除非更改:

  • 闭合类型的大小和/或对齐方式,

  • 闭包类型是普通可复制([class.prop])还是(2.3)

  • 闭合类型是否为标准布局类([class.prop])。

实现不得将右值引用类型的成员添加到闭包类型。

重点矿

因此,即使没有捕获,这也允许实现为lambda赋予成员。我认为永远不会有任何实现,但是在法律上允许这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.