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

其他回答

从n3092开始,Const不在捕获语法中:

capture:
  identifier
  & identifier
  this

文本只提到了复制捕获和引用捕获,没有提到任何形式的const-ness。

对我来说,这是一个疏忽,但我没有非常密切地遵循标准化过程。

我想如果你不使用变量作为函子的参数,那么你应该使用当前函数的访问级别。如果你认为不应该,那么把和这个函数分开,它不是函数的一部分。

不管怎样,你可以通过使用另一个const引用来轻松实现你想要的东西:

#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

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

    string best_string = "foo";
    const string& string_processed = best_string;

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

但这和假设你的必须与当前函数隔离是一样的,使它成为非。

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

不要使用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);
}

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

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

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

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

在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