C++ 11 lambda可以捕获文件范围变量吗?

 coraft 发布于 2023-02-13 09:38

ISO C++ 11规范的第5.1.2节第10节规定:

使用通常的非限定名称查找规则(3.4.1)查找捕获列表中的标识符; 每个这样的查找应该找到一个变量,其自动存储持续时间在本地lambda表达式的到达范围内声明.如果实体(即变量或此实体)出现在lambda表达式的捕获列表中,则称其被明确捕获.

这似乎意味着lambda无法捕获文件范围变量.例如,该程序应该是非法的:

#include 

int x = 13;

int main()
{
  auto l = [](){ return x; };

  std::cout << l() << std::endl;

  return 0;
}

但是,g++4.7.1会产生我期望的结果:

$ g++ --version
g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ -std=c++11 lambda.cpp 
$ ./a.out 
13

clang3.0崩溃:

$ clang --version
Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0)
Target: i386-pc-linux-gnu
Thread model: posix
$ clang -std=c++11 lambda.cpp 
0  libLLVM-3.0.so.1 0xb70a59e8
1  libLLVM-3.0.so.1 0xb70a5f34
2                   0xb775d400 __kernel_sigreturn + 0
3  clang            0x0869f2e9 clang::Sema::DeduceAutoType(clang::TypeSourceInfo*, clang::Expr*, clang::TypeSourceInfo*&) + 73

我的程序是非法的吗?如果它是非法的,禁止捕获文件范围变量的理由是什么?

1 个回答
  • 出于名称查找的目的,lambda的主体被认为是在lambda表达式的上下文中.也就是说,名称查找就像使用lambda之外的名称一样.见[expr.prim.lambda]/7.例如:

    #include <iostream>
    
    int x = 13;
    int y = 0;
    
    int main()
    {
      static int y = 42;
      int z = 1729;
    
      auto l = [/*forget about the capture for a moment*/]()
      { return x+y+z; };
      // find the names x,y,z as if they had been mentioned outside the lambda
      // find the locals y, z and the global x
    
      std::cout << l() << std::endl;
    
      return 0;
    }
    

    现在,您需要捕获自动存储持续时间的变量.我想这会使它更容易出错,因为你可以复制并返回lambdas,这样在调用lambda时自动变量就被破坏了:

    int main()
    {
      static int y = 42;
    
      std::function<int()> f;
      {
        int z = 1729;
    
        f = [](){ return x+y+z; }; // imagine we could do this
      }
    
      std::cout << f() << std::endl; // uh-oh!
    
      return 0;
    }
    

    当然,对于具有静态存储持续时间的变量,不会出现此问题.

    具体来说,[expr.prim.lambda]/12说:

    如果lambda表达式或函数的实例化调用一般lambda odr使用的操作符模板(3.2)this或具有自其存储持续时间的变量,则该实体应由lambda表达式捕获.

    非自动变量也可以通过名称查找找到,但不受此规则的影响.您可以使用它们而无需捕获.


    注意,使用odr的放松允许使用自动变量来捕获它们,例如:

    int main()
    {
      int x = 42;
      constexpr int y = 1789;
    
      auto l = []() -> int
      {
          decltype(x) my_var = 100;  // no odr-use of `x`
          return my_var*y;           // no odr-use of `y`
      };
    
      std::cout << l() << std::endl;
    
      return 0;
    }
    

    2023-02-13 09:43 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有