【问题标题】:Should we capture by const reference in lambda?我们应该通过 lambda 中的 const 引用来捕获吗?
【发布时间】:2018-11-19 14:25:58
【问题描述】:

我一直在阅读Lambda capture as const reference?
这是一个有趣的功能,有时我也希望这个功能存在,尤其是当我有大量数据时,我需要在 lambda 函数中访问这些数据。

我的后续问题 -

  • 我们应该通过 lambda 中的 const 引用来捕获吗?如果是,它应该如何表现?
    (编辑 - 我也对捕获变量的生命周期的行为感兴趣。)
  • 在 C++ 语法中引入它有什么可能的缺点吗?(我想不出来)

假设我们可以。
我们假设[const &] 是要捕获的语法。

int x = 10;
auto lambda = [const & x](){ std::cout << x << std::endl; }; 
lambda(); // prints 10, great, as expected

x = 11;
lambda(); // should it print 11 or 10 ?

我的直觉是它的行为应该像[&amp;],但不应该允许修改捕获的值。

template<typename Func>
void higher_order_function(int & x, Func f)
{
    f(); // should print 11
    x = 12;
    f(); // should print 12
}

void foo()
{
    int x = 10;
    auto c = [const & x] () { std::cout << x << std::endl; };

    c(); // should print 10
    x = 11;
    c(); // should print 11
    higher_order_function(x, c);

    auto d = [const & x] () { x = 13; }; // Compiler ERROR: Tried to assign to const qualified type 'const int &'!
} 

【问题讨论】:

  • 您对const 的含义犯了一个常见错误。 const 没有描述一个值——只有一个特定的符号。它表示“值不会改变”。这意味着“这个特定的符号不会改变值”
  • 尝试编译时 (clang++ -std=c++14) 我收到此错误:expected variable name or 'this' in lambda capture list。我怎样才能编译这个? (我删除了最后一条语句)。

标签: c++ c++11 closures c++14 constants


【解决方案1】:

我自己也一直在想这个。
由于 operator() 默认为 const,我认为允许 const 引用也是可以接受的。

使用当前标准(C++17),我最接近这种行为的是:

auto c = [ &x = std::as_const(x) ] () { std::cout << x << std::endl; };

C++11/C++14 中的解决方法是(感谢 Daniel 的建议):

auto const & crx = x;
auto c = [ &crx ] () { std::cout << crx << std::endl; };

【讨论】:

  • 请注意,从 C++17 开始有效。在 C++11 中,您可以选择使用 const int &amp; crx = x; 并捕获 crx 而不是 x
【解决方案2】:
lambda(); // should it print 11 or 10 ?

我不明白为什么它应该打印 10。考虑lambda 只是某个匿名类的一个实例。让它成为一个普通的类,它应该看起来像:

class Lambda {
   public:
      Lambda(const int & i) : i_(i) { }
      void operator()() { std::cout << i_ << std::endl; }
   private:
      const int & i_;
 };

int x = 10;
Lambda lambda(x);
lambda(); // prints 10, great, as expected

x = 11;
lambda(); // should it print 11 or 10 ?

这里const引用的意思只是不能修改xi_的成员引用变量。


一个更简单的场景:

int x = 10;
const int & crx = x;
x++;
std::cout << crx << std::endl; // prints 11

【讨论】:

  • 问题是,是否应该有语言扩展。
  • @kiloalphaindia 由于有多个问题,我并不清楚 OP 在问什么。 // should it print 11 or 10 ?这也是一个问题。
  • @DanielLangr,感谢您的解释。我对“通过在 C++ 语法中引入它是否有任何可能的缺点?”更感兴趣。对此有何见解或见解?
【解决方案3】:

也许不完全是您正在寻找的东西,但是...我想您可以通过一个通过 const 引用接收相同值的函数。

如下

template <typename T>
auto make_capture_const (T const & x)
 { return [&x](){ std::cout << x << std::endl; }; }

// ...

int x { 42 };

auto l = make_capture_const(x);

l();

如果您尝试在 lambda 中修改 x

std::cout << x++ << std::endl;

你应该得到一个错误。

如您所见,从这个解决方案中,您可以得到 x 不能在 lambda 内部修改,但 lambda 会受到外部值变化的影响

   int x { 42 };

   auto l = make_capture_const(x);

   l();  // print 42

   x = 43;

   l();  // print 43

恕我直言,假设的[const &amp;] 捕获语法应该以相同的方式工作。但我知道这是非常值得怀疑的。

【讨论】:

  • 在C++17中,也可以使用auto lambda = [&amp;x = std::as_const(x)]{ std::cout &lt;&lt; x &lt;&lt; std::endl; };
  • @DanielLangr - 有趣;我不知道。
  • @max66 ,感谢您的解释。我对“通过在 C++ 语法中引入它是否有任何可能的缺点?”更感兴趣。对此有何见解或见解?
  • 我想缺点是如果 lambda 通过引用捕获,则无法将其传递出函数范围。如果不需要修改值,为什么要限制可移植性?
猜你喜欢
  • 1970-01-01
  • 2015-09-25
  • 2010-09-10
  • 1970-01-01
  • 2020-01-23
  • 2016-02-08
  • 1970-01-01
  • 2019-08-28
相关资源
最近更新 更多