是否可以通过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月)

有帮助吗?

解决方案

const 截至N3092,不在语法上:

capture:
  identifier
  & identifier
  this

文本仅提及逐行和逐个捕获,并且没有提及任何形式的const。

对我来说感觉就像是一种疏忽,但我没有非常紧密地遵循标准化过程。

其他提示

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

我认为捕获部分不应指定 const, ,作为捕获手段,它只需要一种访问外部范围变量的方法。

在外部范围中更好地指定了指定符。

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

lambda功能 是const(无法在其范围中更改值),因此当您按值捕获变量时,变量无法更改,但是引用不在lambda范围中。

我猜如果您不使用变量作为函数的参数,则应使用当前函数的访问级别。如果您认为不应该这样做,那么将您的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。

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

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

使用副本

关于Lambdas和Copy Capture的有趣部分是,这些部分实际上仅读取,因此完全按照您想要的操作。

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

使用std :: bind

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

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

有一个较短的方法。

请注意,在“ BEST_STRING”之前没有AMPERS。

它将是“ const std :: reference_wrapper << t >>” type。

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

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

使用clang或等到修复此GCC错误:BUG 70385:通过参考const引用失败捕获lambda [https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385]

使用const将简单地具有算法and和将字符串设置为原始值,换句话说,lambda不会真正将自己定义为函数的参数,尽管周围范围将具有额外的变量...不过,它不会将字符串定义为典型 &&best_string](字符串const s) 所以, ,如果我们只是将其留下来,试图捕获参考,那就更好了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top