11

我正在尝试通过(可变)lambda 中的副本来捕获 const 对象。然而,我的编译器抱怨说,捕获的对象是 const。

不能将对象复制为非常量吗?

struct Foo
{
    Foo(){}
    void Func(){}
};

int main()
{
    const Foo foo;
    [foo]() mutable { foo.Func(); };
}

使用 g++ 4.7.2 编译:

testcase.cpp: In lambda function:
testcase.cpp:10:29: error: no matching function for call to ‘Foo::Func() const’
testcase.cpp:10:29: note: candidate is:
testcase.cpp:4:7: note: void Foo::Func() <near match>
testcase.cpp:4:7: note:   no known conversion for implicit ‘this’ parameter from ‘const Foo*’ to ‘Foo*’

使用 clang++ 3.1 编译:

testcase.cpp:10:20: error: member function 'Func' not viable: 'this' argument has type 'const Foo', but function is not marked const
    std::async([foo]() mutable { foo.Func(); });

标准文档(或者更确切地说是草案...)在 5.1.2.14 中定义“类型 [...] 是相应捕获实体的类型”,所以我想这将包括 cv 说明符。
但它似乎并不直观。

4

3 回答 3

7

首先,具有捕获的 lambda 表达式的类型是类类型(5.1.2 Lambda 表达式 [expr.prim.lambda] #3)

operator()默认情况下,该类型有一个which const,除非mutable在 lambda 表达式中使用 ([expr.prim.lambda] #5)

接下来,对于作为副本捕获的每个实体,在闭包类型中声明一个未命名的成员。[expr.prim.lambda] #14]

如果您显式构建(大部分)等效的捕获类型,那么一切自然会遵循类、const 限定类型和 const 限定成员函数的通常语义。

例子:

struct S
{
  void f();
  void fc() const;
};

void g()
{
  S s0;

  // [s0] ()  { s0.f(); }; // error, operator() is const
  [s0] () { s0.fc(); };    // OK, operator() is const, S::fc is const

  [s0] () mutable { s0.f(); };
  [s0] () mutable { s0.fc(); };

  const S s1;

  // [s1] ()  { s1.f(); }; // error, s1 is const, no matter if operator() is const
  [s1] ()  { s1.fc(); };

  // [s1] () mutable { s1.f(); }; // error, s1 is const, no matter if operator() is const
  [s1] () mutable { s1.fc(); };
}

我想这种混淆源于这样一个事实,即mutable在 lambda 声明器中,关注的const是的 -ness operator(),而不是mutable闭包类型的数据成员的 -ility。const使用成员函数会更自然,但我猜标准委员会希望const成为默认值。

于 2012-12-04T10:32:28.550 回答
1

这将在 C++14 下工作,而不是 C++11 的解决方案。

struct Foo
{
    Foo(){}
    void Func(){}
};

int main()
{
    const Foo foo;
    [foo = foo]() mutable { foo.Func(); };
}

但我真的不明白为什么[foo]保留 const 而[foo = foo]不是。

于 2019-02-22T09:08:33.157 回答
0

另一种可能的解决方法:

  struct Foo
  {
      Foo(){}
      void Func(){}
  };

  int main()
  {
      const Foo foo;
      {
          Foo& fooo= const_cast<Foo&>(foo);
          [fooo]() mutable { fooo.Func(); };
      }
  }

此方案存在安全问题(可能通过非 const 引用意外修改 const 对象),但避免了额外的复制。

于 2012-12-04T13:00:19.930 回答