Лямбда-захват как 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;
}

Обновление. Поскольку это старый вопрос, может быть полезно обновить его, если в С++ 14 есть возможности для этого. Расширяются ли расширения в С++ 14, чтобы мы могли захватить объект non-const посредством ссылки const? (Август 2015 г.)

Ответ 1

const не находится в грамматике для захватов с n3092:

capture:
  identifier
  & identifier
  this

В тексте упоминается только захват за копией и запись по ссылке и не упоминается какая-либо константа.

Похоже на меня, но я не очень внимательно следил за процессом стандартизации.

Ответ 2

Обновление. Поскольку это старый вопрос, может быть полезно обновить его, если в С++ 14 есть возможности для этого. Расширения в С++ 14 позволяют нам захватывать неконстантный объект по ссылке const?

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

DEMO

Ответ 3

Я думаю, что часть захвата не должна указывать const, как средство захвата, ему нужен только способ доступа к внешней переменной сферы.

Спецификатор лучше указывается во внешней области.

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

lambda function - const (не может изменять значение в своей области), поэтому, когда вы фиксируете переменную по значению, переменная не может быть изменена, но ссылка не находится в области лямбда.

Ответ 4

Я предполагаю, что если вы не используете переменную в качестве параметра функтора, то вы должны использовать уровень доступа к текущей функции. Если вы считаете, что вам этого не следует, отделите свою лямбду от этой функции, это не ее часть.

Во всяком случае, вы можете легко достичь того же, чего хотите, используя вместо него другую ссылку:

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

Но так же, как и предполагать, что ваша лямбда должна быть изолирована от текущей функции, делая ее не-лямбдой.

Ответ 5

Я думаю, у вас есть три разных варианта:

  • не используйте ссылку const, но используйте захват копирования
  • игнорировать тот факт, что он модифицируется
  • используйте std:: bind для привязки одного аргумента двоичной функции, которая имеет константную ссылку.

с помощью копии

Интересная часть о лямбдах с копиями заключается в том, что они на самом деле только для чтения и, следовательно, делают именно то, что вы хотите.

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

Ответ 6

Существует более короткий путь.

Обратите внимание, что перед "best_string" нет амперсанда.

Он будет иметь тип "const std:: reference_wrapper < T → ".

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

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

Ответ 7

Используйте clang или подождите, пока не будет исправлена ​​ошибка gcc: ошибка 70385: Лямбда-захват по ссылке const ссылается на ошибку [https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385]