简体   繁体   English

Lambda 捕获作为常量引用?

[英]Lambda capture as const reference?

Is it possible to capture by const reference in a lambda expression?是否可以通过 lambda 表达式中的常量引用进行捕获?

I want the assignment marked below to fail, for example:我希望下面标记的作业失败,例如:

#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;
}

Update: As this is an old question, it might be good to update it if there are facilities in C++14 to help with this.更新:由于这是一个老问题,如果 C++14 中有工具可以帮助解决这个问题,最好更新它。 Do the extensions in C++14 allow us to capture a non-const object by const reference? C++14 中的扩展是否允许我们通过常量引用捕获非常量对象? ( August 2015 ) 2015 年 8 月

In using static_cast / const_cast :使用static_cast / const_cast

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

DEMO演示


In using std::as_const :使用std::as_const

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

DEMO 2演示 2

const isn't in the grammar for captures as of n3092:自 n3092 起, const不在捕获的语法中:

capture:
  identifier
  & identifier
  this

The text only mention capture-by-copy and capture-by-reference and doesn't mention any sort of const-ness.文本仅提及按复制捕获和按引用捕获,并没有提及任何类型的常量。

Feels like an oversight to me, but I haven't followed the standardization process very closely.对我来说感觉像是疏忽,但我并没有非常密切地遵循标准化过程。

I think the capture part should not specify const , as the capture means, it only need a way to access the outer scope variable.我认为捕获部分不应该指定const ,因为捕获意味着,它只需要一种访问外部作用域变量的方法。

The specifier is better specified in the outer scope.说明符最好在外部范围内指定。

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

lambda function is const(can't change value in its scope), so when you capture variable by value, the variable can not be changed, but the reference is not in the lambda scope. lambda 函数是 const(不能在其作用域内改变值),所以当你按值捕获变量时,变量不能改变,但引用不在 lambda 作用域内。

I guess if you're not using the variable as a parameter of the functor, then you should use the access level of the current function.我想如果您不使用变量作为函子的参数,那么您应该使用当前函数的访问级别。 If you think you shouldn't, then separate your lambda from this function, it's not part of it.如果你认为你不应该,那么把你的 lambda 与这个函数分开,它不是它的一部分。

Anyway, you can easily achieve the same thing that you want by using another const reference instead :无论如何,您可以通过使用另一个常量引用轻松实现您想要的相同内容:

#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;
}

But that's the same as assuming that your lambda have to be isolated from the current function, making it a non-lambda.但这与假设您的 lambda 必须与当前函数隔离,使其成为非 lambda 相同。

I think you have three different options:我认为您有三种不同的选择:

  • don't use const reference, but use a copy capture不要使用常量引用,而是使用副本捕获
  • ignore the fact that it is modifiable忽略它是可修改的事实
  • use std::bind to bind one argument of a binary function which has a const reference.使用 std::bind 绑定具有 const 引用的二元函数的一个参数。

using a copy使用副本

The interesting part about lambdas with copy captures is that those are actually read only and therefore do exactly what you want them to.带有复制捕获的 lambda 的有趣之处在于它们实际上是只读的,因此完全按照您的要求执行。

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

using std::bind使用 std::bind

std::bind reduces the arity of a function. std::bind减少了函数的数量。 Note however that this might/will lead to an indirect function call via a function pointer.但是请注意,这可能/将导致通过函数指针进行间接函数调用。

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

There is a shorter way.有一个更短的方法。

Note that there is no ampersand before "best_string".请注意,“best_string”之前没有&符号。

It will be of a "const std::reference_wrapper<< T >>" type.它将是“const std::reference_wrapper<< T >>”类型。

[best_string = cref(best_string)](const string& s)
{
    best_string = s; // fails
};

http://coliru.stacked-crooked.com/a/0e54d6f9441e6867 http://coliru.stacked-crooked.com/a/0e54d6f9441e6867

使用 clang 或等到此 gcc 错误修复:错误 70385:通过引用常量引用的 Lambda 捕获失败 [ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385 ]

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM