lambda闭包中复制的const对象不可变

时间:2012-12-04 09:18:47

标签: c++ c++11 lambda

我试图通过(可变)lambda中的副本捕获一个const对象。然而,我的编译器抱怨说,捕获的对象是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中定义&#34;类型[...]是相应的捕获实体的类型&#34;,所以我想这将包括cv-specifiers 但这似乎并不直观。

3 个答案:

答案 0 :(得分:6)

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

该类型的operator()默认为const,除非在lambda表达式中使用mutable([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(); };
}

我想混淆源于这样一个事实:lambda声明符中的mutable涉及const的{​​{1}} - 而不是operator() - {闭包类型的数据成员。与成员函数一样,使用mutable会更自然,但我想标准委员会希望const成为默认值。

答案 1 :(得分:1)

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

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

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

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

答案 2 :(得分:0)

另一种可能的解决方法:

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

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

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