Изменение всех элементов в векторе (list, deque …) с использованием лямбда-функций C 11

#c #lambda #c 11

#c #лямбда #c 11

Вопрос:

У меня есть следующий код:

 #include <iostream>
#include <vector>
#include <algorithm>

int main( int argc, char* argv[] )
{
    std::vector< int > obj;
    obj.push_back( 10 );
    obj.push_back( 20 );
    obj.push_back( 30 );
    std::for_each( obj.begin(), obj.end(), []( int x )
    { 
        return x   2; 
    } );
    for( int amp;v : obj )
        std::cout << v << " ";
    std::cout << std::endl;
    return 0;
}
  

Результат: 10, 20, 30

я хочу изменить все элементы в векторе (obj), используя лямбда-функции нового стандарта C 11.

Это код реализации for_each функции:

 template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f)
{
    for ( ; first!=last;   first )
        f(*first);
    return f;
}
  

* изменено значение, переданное первым, и изменен код элемента, какую альтернативу for_each я должен использовать, чтобы получить результат: 12, 22, 32?

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

1. Вам нужно использовать lambda со ссылками. Я не знаю точного синтаксиса, но это было что-то вроде: [amp;](int x){ ..}

2. @KirilKirov amp; Внутренняя часть [] фиксирует окружающую среду (локальные переменные) по ссылке. Что ему нужно, так это просто ссылка на входной аргумент: [](int amp;x) .

3. @ChristianRau — спасибо. Я еще не изучал новый стандарт, я просто прочитал кое-что в википедии и не помню всего этого.

Ответ №1:

я хочу изменить все элементы в векторе (obj), используя лямбда-функции нового стандарта C 11.

Вы должны сделать это :

 std::for_each( obj.begin(), obj.end(), [](int amp; x)
{                                          //^^^ take argument by reference
   x  = 2; 
});
  

В вашем (не моем) коде возвращаемый тип лямбды выводится как int , но возвращаемое значение игнорируется, поскольку его никто не использует. Вот почему в моем коде нет оператора return, а возвращаемый тип выводится как void для этого кода.

Кстати, я нахожу for цикл на основе диапазона менее подробным, чем std::for_each для этой цели:

 for( int amp;v : obj )  v  = 2;
  

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

1. Вы должны указать return в своем теле лямбда-выражения, должна ли функция возвращать что-либо.

2. @wilhelmtell: Lambda ничего не возвращает.

Ответ №2:

Вам следует использовать transform :

 std::transform( obj.begin(), obj.end(), obj.begin(), []( int x )
{ 
    return x   2; 
} );
  

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

1. Я думаю, for_each это так же ясно, transform имеет больше смысла, когда вы используете пункт назначения, а не источник. В любом случае, если мы говорим «должны», я думаю, это то, что должно быть сделано: for(autoamp; x : obj) x = 2;

2. Я думаю, что оба std::transform() и цикл for на основе диапазона являются хорошим кодом здесь. std::transform() говорит более семантически и for указывает меньше точек. Таким образом, вы можете утверждать в любом случае.

Ответ №3:

Передайте аргумент по ссылке и измените ссылку:

 std::for_each( obj.begin(), obj.end(), [](int amp; x){ x  = 2; } );
//                                        ^^^^^
  

Ответ №4:

 std::for_each( obj.begin(), obj.end(), []( intamp; x )
{ 
     x  = 2; 
} );
  

Ответ №5:

В дополнение к уже существующим (и совершенно правильным) ответам, вы также можете использовать свою существующую лямбда-функцию, которая возвращает результат вместо изменения аргумента, и просто использовать std::transform вместо std::for_each :

 std::transform(obj.begin(), obj.end(), obj.begin(), []( int x )
{
    return x   2;
} );