是否有可能在lambda表达式中通过const引用捕获?

我希望下面标记的作业失败,例如:

#include <algorithm>
#include <string>

using namespace std;

int main()
{
    string strings[] = 
    {
        "hello",
        "world"
    };
    static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);

    string best_string = "foo";

    for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
      {
        best_string = s; // this should fail
      }
    );
return 0;
}

更新:由于这是一个老问题,如果c++ 14中有帮助解决这个问题的工具,更新它可能会很好。c++ 14中的扩展允许我们通过const引用捕获非const对象吗?(2015年8月)


当前回答

我认为捕获部分不应该指定const,因为捕获意味着,它只需要一种访问外部作用域变量的方法。

说明符最好在外部作用域中指定。

const string better_string = "XXX";
[&better_string](string s) {
    better_string = s;    // error: read-only area.
}

Lambda函数是const(不能在其作用域中更改值),因此当您按值捕获变量时,变量不能更改,但引用不在Lambda作用域中。

其他回答

我认为你有三个不同的选择:

不要使用const引用,而是使用副本捕获 忽略它是可修改的事实 使用std::bind绑定具有const引用的二进制函数的一个实参。

使用副本

带有复制捕获的lambdas的有趣之处在于,它们实际上是只读的,因此完全按照您的要求执行。

int main() {
  int a = 5;
  [a](){ a = 7; }(); // Compiler error!
}

使用std::绑定

bind降低函数的元数。但是请注意,这可能/将导致通过函数指针间接调用函数。

int main() {
  int a = 5;
  std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a);
}

在c++14中使用static_cast / const_cast:

[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
    best_string = s; // fails
};

DEMO


在c++17中使用std::as_const:

[&best_string = std::as_const(best_string)](const string& s)
{
    best_string = s; // fails
};

演示2

我认为捕获部分不应该指定const,因为捕获意味着,它只需要一种访问外部作用域变量的方法。

说明符最好在外部作用域中指定。

const string better_string = "XXX";
[&better_string](string s) {
    better_string = s;    // error: read-only area.
}

Lambda函数是const(不能在其作用域中更改值),因此当您按值捕获变量时,变量不能更改,但引用不在Lambda作用域中。

使用clang或等待,直到这个gcc错误被修复: bug 70385:通过const引用捕获Lambda失败[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385]

使用const只会让算法的&号将字符串设置为它的原始值, 换句话说,lambda不会真正将自己定义为函数的参数,尽管周围的作用域将有一个额外的变量…… 如果没有定义它,它不会将字符串定义为典型的 [&, &best_string](字符串常量) 因此,如果我们仅仅停留在那里,尝试捕获引用,很可能会更好。