for_each как лямбда-функция

#c #lambda

Вопрос:

Я попытался написать for_each как лямбда-функцию, где каждое значение a std::array должно быть скопировано в другое. Мой текущий код выглядит так:

 std::random_device rd;
    std::default_random_engine eng(rd());
    std::uniform_int_distribution<int> distr(MIN, MAX);

    std::array<int, 20> random_numbers;

    std::cout << "Original: " << std::endl;

    

    for (int i = 0; i != random_numbers.size(); i  ) {
        random_numbers[i] = distr(eng);
        std::cout << random_numbers[i] << std::endl;
    }


    auto copy_numbers = std::for_each(random_numbers.begin(), random_numbers.end(), [n = 20](const std::array<int, 20> rn) {
        return rn.at(n);
    });
 

Однако с моей лямбда-функцией что-то не так. :: operator () (const std :: array <_Ty, 20>) const": Conversion of argument 1 from "_Ty" to "const std :: array <int, 20> "not possible . Кто-нибудь знает, что не так с функцией?

Комментарии:

1.Похоже, вам просто нужно auto copy_numbers = random_numbers; std::for_each перебрать каждый элемент и что-то с ним сделать.

2. std::for_each (1) ожидает вызываемый объект, который принимает один элемент в качестве параметра, в отличие от всего контейнера, и (2) возвращает этот вызываемый объект. Поэтому, что бы вы ни пытались с этим сделать, скорее всего, лучше сделать с чем-то другим.

Ответ №1:

 std::array<int, 20> random_numbers;
 

Это контейнер int с s. Итерация по этому контейнеру приведет int к повторению значений.

std::for_each это просто повторение последовательности, определенной начальным и конечным итератором, а затем вызывает вызываемый объект со ссылкой на каждое значение в последовательности. Это все, что он делает, и ни одной вещи в дополнение к этому.

 [n = 20](const std::array<int, 20> rn) {
 

Параметром этого вызываемого объекта является a std::array . Однако, как я объяснил выше, std::for_each этот вызываемый объект передаст ссылку на каждое значение в последовательности. Что является int . Вы не можете преобразовать an int в a std::array<int, 20> , это недопустимое преобразование.

 return rn.at(n);
 

Здесь есть ряд проблем, но главная из них заключается в том, что std::for_each абсолютно ничего не делает с тем, что возвращает вызываемый объект. Возвращаемое значение полностью игнорируется. Все, что std::for_each нужно сделать, это повторить последовательность, определенную ее первыми двумя параметрами, и вызвать третий параметр со ссылкой на каждое значение в последовательности. На этом его работа завершена.

 auto copy_numbers = std::for_each(
 

std::for_each возвращает копию своего третьего параметра. То, что вы получите здесь, — это копия анонимной лямбды, а не что-либо, связанное с исходной последовательностью. Вы ожидаете получить здесь копию оригинального контейнера, но это не то, что std::for_each возвращается.

Создается впечатление, что std::for_each вы вызываете вызываемый объект для каждого значения в последовательности, а затем используете возвращаемое значение вызываемого объекта для создания нового контейнера. Однако это не то, что std::for_each делает. Это отдаленно похоже на то, что std::transform делает, но делает это принципиально по-другому, а не так.

Ответ №2:

1.Вы не можете инициализировать n во время захвата, вы должны объявить n в другом месте и захватить его.

2. std::for_each может быть реализовано следующим образом:

 template<class InputIt, class UnaryFunction>
constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
    for (; first != last;   first) {
        f(*first);
    }
    return f; // implicit move since C  11
}
 

как вы можете видеть, возвращаемый тип лямбда-кода-это не массив, а указатель на функцию f, поэтому вы не можете просто скопировать любое std::for_each возвращаемое значение в переменную в виде массива.

То, что вы намеревались сделать, можно сделать с помощью следующего кода

 int n=0;
std::array<int, 20> copy_numbers;
std::for_each(random_numbers.begin(), random_numbers.end(), [amp;n, amp;copy_numbers](int a){
    copy_numbers[n  ] = a;
});
 

Кстати, вот некоторые дополнительные сведения.

https://www.learncpp.com/cpp-tutorial/lambda-captures/

https://en.cppreference.com/w/cpp/algorithm/for_each