Подтвердить что ты не робот

Какова мотивация лямбда-выражений С++ 11?

Я пытаюсь выяснить, есть ли реальная вычислительная выгода для использования лямбда-выражений в С++, а именно: "этот код компилируется/работает быстрее/медленнее, потому что мы используем лямбда-выражения", или это просто аккуратный приступ развития, открытый для злоупотреблений бедные кодеры пытаются выглядеть круто?

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

4b9b3361

Ответ 1

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

Ответ 2

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

С++ позволяет, в определенной степени, выполнять функциональное программирование. Рассмотрим это:

std::for_each( begin, end, doer );

Проблема заключается в том, что функция (объект) doer

  • указывает сделанное в цикле
  • пока несколько скрывает то, что на самом деле сделано (вам нужно искать реализацию объекта operator())
  • должен быть определен в другой области, чем вызов std::for_each
  • содержит определенное количество шаблона
  • часто код выброса, который не используется ни для чего, кроме этой однострочной конструкции

Lambdas значительно улучшает все это (и, возможно, еще немного забыл).

Ответ 3

Там нет преимуществ по производительности, но потребность в лямбда возникла вследствие широкого внедрения STL и его дизайнерских идей.

В частности, алгоритмы STL часто используют функторы. Без лямбда эти функторы должны быть предварительно объявлены для использования. Lambdas позволяет иметь "анонимных", функторов на месте.

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

Я, например, много использую STL, но без С++ 0x я использую гораздо больше для циклов(), чем алгоритм for_each() и его кузенов. Это потому, что, если бы я использовал вместо for_each(), мне нужно было бы получить код внутри цикла и объявить для него функтором. Кроме того, все локальные переменные перед циклом не будут доступны, поэтому мне нужно будет написать дополнительный код, чтобы передать их в качестве параметров конструктору-функтора или эквивалент другой вещи. Как следствие, я склонен не использовать for_each(), если нет сильной мотивации, иначе код будет длиннее и труднее читать.

Это плохо, потому что хорошо известно, что использование for_each() и подобных алгоритмов дает гораздо больше возможностей для компилятора и библиотеки для оптимизации, включая автоматический parallelism. Таким образом, косвенно, лямбда будет способствовать более эффективному коду.

Ответ 4

IMO, самое важное в лямбда - это связанный с ним код близко друг к другу. Если у вас есть этот код:

std::for_each(begin, end, unknown_function);

Вам нужно перейти к unknown_function, чтобы понять, что делает код. Но с лямбдой логику можно держать вместе.

Ответ 5

Lambdas - синтаксический сахар для классов-функторов, поэтому нет, нет вычислительной выгоды. Что касается мотивации, возможно, любой из других десятков или около того популярных языков, в которых есть лямбды?

Можно утверждать, что это помогает в удобочитаемости кода (если ваш функтор объявлен встроенным, где он используется).

Ответ 6

Хотя я думаю, что другие части С++ 0x более важные, lambdas - это больше, чем просто "синтаксический сахар" для объектов функции стиля С++ 98, потому что они могут захватывать контексты, и они делают это по имени, а затем могут принимать эти контексты в другом месте и выполнять. Это нечто новое, а не то, что "компилируется быстрее/медленнее".

#include <iostream>
#include <vector>
#include <functional>
void something_else(std::function<void()> f)
{
        f(); // A closure! I wonder if we can write in CPS now...
}
int main()
{
        std::vector<int> v(10,0);
        std::function<void ()> f = [&](){ std::cout << v.size() << std::endl; };

        something_else(f);
}

Ответ 7

Ну, сравните это:

int main () {
    std::vector<int> x = {2, 3, 5, 7, 11, 13, 17, 19};

    int center = 10;
    std::sort(x.begin(), x.end(), [=](int x, int y) {
        return abs(x - center) < abs(y - center);
    });

    std::for_each(x.begin(), x.end(), [](int v) {
        printf("%d\n", v);
    });

    return 0;
}

с этим:

// why enforce this to be defined nonlocally?
void printer(int v) {
    printf("%d\n", v);
} 

int main () {
    std::vector<int> x = {2, 3, 5, 7, 11, 13, 17, 19};

    // why enforce we to define a whole struct just need to maintain a state?
    struct {
        int center; 
        bool operator()(int x, int y) const {
            return abs(x - center) < abs(y - center);
        }
    } comp = {10};

    std::sort(x.begin(), x.end(), comp);

    std::for_each(x.begin(), x.end(), printer);

    return 0;
}

Ответ 8

"аккуратный приступ развития, открытый для злоупотреблений со стороны слабых кодеров, пытающихся выглядеть круто?"... как бы вы это ни называли, он делает код лот более читабельным и поддерживаемым. Это не увеличивает производительность.

Чаще всего программист выполняет итерацию по ряду элементов (поиск элемента, накопления элементов, элементов сортировки и т.д.). Используя функциональный стиль, вы сразу же видите, что программист намеревается делать, так как он отличается от использования для циклов, где все "выглядит" одинаково.

Сравнить алгоритмы + lambda:

iterator longest_tree = std::max_element(forest.begin(), forest.end(), [height]{arg0.height>arg1.height});
iterator first_leaf_tree = std::find_if(forest.begin(), forest.end(), []{is_leaf(arg0)});
std::transform(forest.begin(), forest.end(), firewood.begin(), []{arg0.trans(...));
std::for_each(forest.begin(), forest.end(), {arg0.make_plywood()});

с помощью oldschool for-loops;

Forest::iterator longest_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
   if (*it.height() > *longest_tree.height()) {
     longest_tree = it;
   }
}

Forest::iterator leaf_tree = it.begin();
for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
   if (it->type() == LEAF_TREE) {
     leaf_tree  = it;
     break;
   }
}

for (Forest::const_iterator it = forest.begin(), jt = firewood.begin(); 
     it != forest.end(); 
     it++, jt++) {
          *jt = boost::transformtowood(*it);
    }

for (Forest::const_iterator it = forest.begin(); it != forest.end(); ++it{
    std::makeplywood(*it);
}

(Я знаю, что этот код кода содержит синтаксические ошибки.)