#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;
});
Кстати, вот некоторые дополнительные сведения.