【问题标题】:Are captureless lambda guaranteed to be empty by the standard?标准是否保证无捕获 lambda 为空?
【发布时间】:2020-05-13 03:00:19
【问题描述】:

我正在寻找一种方法来从模板函数中的其他 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_empty 产生 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?

Live example

【问题讨论】:

  • 如果您只关心非模板 lambda,您可以使用 SFINAE 检查转换为函数指针 (+lambda) 的格式是否正确。
  • @HolyBlackCat 我想过,但据我记得,MSVC 不允许这样做,因为它们重载了转换运算符。
  • @GuillaumeRacicot MS 为所有可用的调用约定公开了一个单独的转换运算符。只需选择一个并尝试将 lambda 转换为可比较的函数指针,然后检查是成功还是失败。
  • + 似乎可以工作 here

标签: c++ lambda c++17 c++20


【解决方案1】:

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

闭包类型在包含相应 lambda 表达式的最小块作用域、类作用域或命名空间作用域中声明。 [注意:这决定了与闭包类型([basic.lookup.argdep])关联的命名空间和类的集合。 lambda-declarator 的参数类型不会影响这些关联的命名空间和类。 — 尾注] 闭包类型不是聚合类型。 实现可以定义不同于下面描述的闭包类型,前提是这不会改变程序的可观察行为,除非通过更改:

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

  • 闭包类型是否可以简单复制([class.prop]),或者 (2.3)

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

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

强调我的

所以这允许实现给 lambda 一个成员,即使它是无捕获的。我认为任何实现都不会,但法律允许他们这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-29
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多