【问题标题】:Why does capturing a variable make the type of a lambda unique? [duplicate]为什么捕获变量会使 lambda 的类型独一无二? [复制]
【发布时间】:2019-11-12 12:52:04
【问题描述】:

在以下最小示例中:

int main()
{
    const int foo = 1;
    const auto a = foo == 1 ? [](){return 42;} : [](){return 4;};
    const auto b = foo == 1 ? [foo](){return 42;} : [foo](){return 4;};
}

a 很好。 b 然而不是,因为:

<source>:5:29: error: incompatible operand types ('(lambda at <source>:5:31)' and '(lambda at <source>:5:53)')

    const auto b = foo == 1 ? [foo](){return 42;} : [foo](){return 4;};
                            ^ ~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~

为什么会这样?又如何获得预期的b

【问题讨论】:

  • foo 的常量可能与潜在问题有关,但与所述问题无关。

标签: c++ c++11 lambda c++14


【解决方案1】:

捕获不会使 lambda 唯一;根据定义,lambda 类型已经是唯一的。但是,非捕获 lambda 可以转换为函数指针,这会在您的第一个示例中创建一个通用类型。

你解决你的具体例子如下:

const auto b = [foo](){ return (foo == 1) ? 42 : 4;};

【讨论】:

  • 一个体面的优化器会在消除常量foo时将其转换为const auto b = []() { return 42; }..
  • 我认为它不能删除捕获:/(因为我认为是 ABI)。
  • @Jarod42:在二进制级别,捕获分为三个部分:存储、初始化捕获的值和使用它。第一个无论如何都不能消除,因为即使是非捕获 lambda 也有sizeof &gt; 0。可以省去初始化和使用。
  • 虽然我们可能期望sizeof([](){return 42;}) == 1,但我们有sizeof([foo](){ /*..*/}) &gt;= sizeof (foo),即使优化了foo。 (而我们可能天真地期望大小为 1):-(
  • @Jarod42:这可能是优化器的量子规则:查看结果可以改变它。
【解决方案2】:

lambda 的类型是唯一的,即使它没有捕获任何内容。比较的方式不对,直接比较吧:

auto first{[](){return 42;}};
auto second{[](){return 42;}};
static_assert(not ::std::is_same_v<decltype(first), decltype(second)>);

避免在执行自动推导变量类型时可能隐式转换为指向函数的指针:

auto a = foo == 1 ? [](){return 42;} : [](){return 4;};
static_assert(::std::is_same_v<int ( * ) (void) , decltype(a)>);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    相关资源
    最近更新 更多