Форум программистов, компьютерный форум CyberForum.ru

Какова польза лямбда выражений - C++

Войти
Регистрация
Восстановить пароль
Другие темы раздела
C++ Ввести несколько кирпичей, определить обьем и определить самый большой http://www.cyberforum.ru/cpp-beginners/thread1121634.html
1)Определить N первых членов рекуррентной последовательностиhttp://rghost.ru/53121622.view 2)Ввести N троек чисел a1,b1,c1; a2,b2, c2 an,bn,cn.... обозначающих длины рёбер кирпичей. Определить кирпич с максимальным объемом 3) Ввести натуральное число N определить сумму четных и количество нечетных 4)Используя три различных цикла определить значение. http://rghost.ru/53121792.view
C++ Перевод числа из двоичной системы в десятичную Помогите написать программу для перевода из 2 в 10. Если число делится на 3, то вывести и результат деления http://www.cyberforum.ru/cpp-beginners/thread1121631.html
C++ Помогите написать две небольшие программы по блок схемам
Помогите написать две небольшие программы по блок схемам для уравнения X^3+3X^2+6X-1=0 1.Метод простой итерации 2.Метод Хорд
В матрице, записанной в файл, четные элементы разделить на 4, а к нечетным прибавить 10 C++
Вот условие задачи: В матрице A(6,6) четные элементы разделить на 4, а к нечетным прибавить 10. Вывести полученную матрицу. код: #include <iostream> #include <cstdio> #include <cmath> using namespace std; int main() {
C++ Перегрузка преобразования класса-строка в тип string (и наоборот) http://www.cyberforum.ru/cpp-beginners/thread1121594.html
Помогите, а то не могу разобраться:(( перегрузка преобразования класса-строка в тип string (и наоборот). #include "stdafx.h" #include "iostream" #include <string> #include <algorithm> #include "vector" using namespace std;
C++ Перегрузка констант true и false помогите, а то не могу разобраться =(( перегрузка констант true и false: обращение к экземпляру класса дает значение true, если строка не пустая, иначе false. #include "stdafx.h" #include "iostream" #include <string> #include <algorithm> #include "vector" using namespace std; подробнее

Показать сообщение отдельно
0x10
2452 / 1624 / 238
Регистрация: 24.11.2012
Сообщений: 3,999
18.03.2014, 12:51     Какова польза лямбда выражений
Цитата Сообщение от volodja- Посмотреть сообщение
В таком случае приведите два совершенно не взаимозаменяемых примера, чтоб почувствовать так сказать разницу
Вы можете вообще выбросить из кода все функции, классы, циклы. Написать одну портянку в main - даже будет работать. Другое дело, что поддерживать это будет невозможно.
Суть в том, что одни конструкции можно заменять другими. Просто в Вашем понимании лямбда эквивалентна циклу.

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

Задача такая: пусть у нас есть контейнер структур одного типа, который нужно преобразовать в контейнер структур другого типа. Например, контейнер пар целых чисел в контейнер структур с двумя полями.

Пусть в первом приближении код выглядит вот так:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    for (size_t i = 0; i < source.size(); ++i)
    {
        dest.emplace_back(source[i].first, source[i].second);
    }
 
    for (size_t i = 0; i < dest.size(); ++i)
    {
        std::cout << dest[i].x << " " << dest[i].y << std::endl;
    }
 
    return 0;
}


Это рабочий код, имеющий право на жизнь. Но есть два недостатка.
1. Он недостаточно универсален. Код предполагает, что мы работаем с контейнером, для которого возможен произвольный доступ к элементам. При необходимости заменить std::vector на std::list этот код придется переписывать.
2. Код читается на очень низком уровне. "Для i от 0 до размера контейрера взять i-тый элемент и разместить его в другом контейнере".

Первый недостаток устраняется использованием итераторов. Или даже перескочим через них и воспользуемся циклом foreach.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    for (const auto& item : source)
    {
        dest.emplace_back(item.first, item.second);
    }
 
    return 0;
}

Код стал сильно проще. Он тоже вполне рабочий и правильный. Читается значительно проще: для каждого элемента из контейнера разместить в другой конрейнер новый элемент, сконструировав его на основе текущего. (Скомкано написал, просто лень расписывать)

Но в данном случае это простая операция, которая уже реализована стандартным алгоритмом std::transform.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
struct PairToPoint
{
    Point operator()(const Pair& p) const
    {
        return {p.first, p.second};
    }
};
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    std::transform(source.begin(), source.end(), std::back_inserter(dest),
        PairToPoint());
 
    return 0;
}

Проделал я эту последовательность, чтобы показать: мы цикл заменили на вызов функции. Не на лямбду, не на функтор.

Недостато кода в том, что нам пришлось для простого преобразования создать новую структуру, что само по себе занимает дополнительное место. И вот уже функтор мы можем заменить на лямбду.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    std::transform(source.begin(), source.end(), std::back_inserter(dest),
        [](const Pair& p){ return Point{p.first, p.second}; });
 
    return 0;
}


Что лучше - foreach или использование функции - решать можно по ситуации.
Что предпочесть - написание функтора или лямбды - часто зависит от объема тела. Для однострочников проще использовать лямбду.

Я сейчас не затрагиваю то, что лямбды легко могут захватывать переменные из области где были созданы. Просто хочу показать между чем и чем обычно делается выбор. И нет тут глупой альтернативы типа "цикл или лямбда".

Ну и приведу еще такое извращение. Пример искусственный, но нечто подобное случалось видеть в коде.
Была потребность написать свою функцию уничтожения объекта, чтобы перед вызовом деструктора был вызван еще один метод. Класс был библиотечный, поэтому по сути нужно было написать свою обертку с инициализацией в конструкторе и корректным уничтожением в деструкторе. Поскольку было влом писать свой класс, переиспользовали std::shared_ptr с кастомной функцией удаления. Профит - одна строчка для разового объекта вместо написания полноценного класса. Увлекаться таким не стоит, но опыт забавный.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <memory>
 
struct Data
{
    void Destroy()
    {
        std::cout << "Destroy" << std::endl;
    }
};
 
int main()
{
    {
        std::shared_ptr<Data> data(new Data(),
            [](Data* data) { data->Destroy(); });
    }
 
    return 0;
}
 
Текущее время: 21:29. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru