是否可以通过lambda表达式中的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";
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月)
答案 0 :(得分:107)
const
不在捕获的语法中:
capture:
identifier
& identifier
this
该文本仅提及逐个复制和按引用捕获,并未提及任何类型的常量。
感觉像是对我的疏忽,但我没有非常密切地关注标准化过程。
答案 1 :(得分:79)
C ++ 14:
[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
best_string = s; // fails
};
C ++ 17:
[&best_string = std::as_const(best_string)](const string& s)
{
best_string = s; // fails
};
答案 2 :(得分:13)
我认为捕获部分不应指定const
,因为捕获意味着它只需要一种方法来访问外部范围变量。
在外部范围中更好地指定说明符。
const string better_string = "XXX";
[&better_string](string s) {
better_string = s; // error: read-only area.
}
lambda函数 是const(不能更改其范围内的值),因此当您按值捕获变量时,该变量无法更改,但参考不属于lambda范围。
答案 3 :(得分:8)
我想如果你没有将变量用作仿函数的参数,那么你应该使用当前函数的访问级别。如果你认为你不应该,那么将你的lambda与这个函数分开,它不是它的一部分。
无论如何,你可以通过使用另一个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;
}
但这与假设你的lambda必须与当前函数隔离,使其成为非lambda一样。
答案 4 :(得分:5)
我认为你有三种不同的选择:
关于带有副本捕获的lambdas的有趣部分是那些实际上是只读的,因此完全按照你的意愿行事。
int main() {
int a = 5;
[a](){ a = 7; }(); // Compiler error!
}
std::bind
减少了函数的arity。但请注意,这可能会导致通过函数指针进行间接函数调用。
int main() {
int a = 5;
std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a);
}
答案 5 :(得分:3)
有一条较短的路。
请注意,“best_string”之前没有“&”符号。
它将是“const std :: reference_wrapper&lt;&lt; T&gt;&gt;”类型。
[best_string = cref(best_string)](const string& s)
{
best_string = s; // fails
};
答案 6 :(得分:0)
使用clang或等到修复此gcc错误: 错误70385:通过引用const引用捕获的Lambda失败[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385]
答案 7 :(得分:0)
使用const只会将算法放大器并将字符串设置为原始值, 换句话说,lambda不会真正将自己定义为函数的参数,尽管周围的范围将有一个额外的变量...... 虽然没有定义它,但它不会将字符串定义为典型字符串 [&amp;,&amp; best_string](字符串const s) 因此,如果我们将其留在那里,它最有可能更好,试图捕获参考。