Bind Vs Lambda? - PullRequest
       58

Bind Vs Lambda?

51 голосов
/ 19 декабря 2009

У меня есть вопрос о том, какой стиль предпочтительнее: std :: bind Vs lambda в C ++ 0x. Я знаю, что они служат - как-то - различным целям, но давайте рассмотрим пример пересекающихся функций.

Использование lambda:

uniform_int<> distribution(1, 6);
mt19937 engine;
// lambda style
auto dice = [&]() { return distribution(engine); };

Использование bind:

uniform_int<> distribution(1, 6);
mt19937 engine;
// bind style
auto dice = bind(distribution, engine);

Какой из них мы должны предпочесть? Зачем? предполагая более сложные ситуации по сравнению с упомянутым примером. то есть каковы преимущества / недостатки одного перед другим?

Ответы [ 6 ]

43 голосов
/ 03 января 2011

C ++ 0x лямбда-выражения являются мономорфными, а привязка может быть полиморфной. Вы не можете иметь что-то вроде

auto f = [](auto a, auto b) { cout << a << ' ' << b; }
f("test", 1.2f);

a и b должны иметь известные типы. С другой стороны, tr1 / boost / phoenix / lambda bind позволяет вам сделать это:

struct foo
{
  typedef void result_type;

  template < typename A, typename B >
  void operator()(A a, B b)
  {
    cout << a << ' ' << b;
  }
};

auto f = bind(foo(), _1, _2);
f("test", 1.2f); // will print "test 1.2"

Обратите внимание, что типы A и B не зафиксированы здесь. Только когда f фактически используется, эти два будут выведены.

26 голосов
/ 19 декабря 2009

Как вы сказали, бинды и лямбды не совсем нацелены на одну и ту же цель.

Например, для использования и составления алгоритмов STL, лямбды - явные победители, ИМХО.

Чтобы проиллюстрировать, я помню очень забавный ответ, здесь о переполнении стека, когда кто-то спрашивал идеи о шестнадцатеричных магических числах (например, 0xDEADBEEF, 0xCAFEBABE, 0xDEADDEAD и т. Д.) И ему говорили, что если он будет настоящим программистом C ++, он просто скачал бы список английских слов и использовал бы простой однострочный текст C ++:)

#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

int main()
{
    using namespace boost::lambda;
    std::ifstream ifs("wordsEn.txt");
    std::remove_copy_if(
        std::istream_iterator<std::string>(ifs),
        std::istream_iterator<std::string>(),
        std::ostream_iterator<std::string>(std::cout, "\n"),
        bind(&std::string::size, _1) != 8u
            ||
        bind(
            static_cast<std::string::size_type (std::string::*)(const char*, std::string::size_type) const>(
                &std::string::find_first_not_of
            ),
            _1,
            "abcdef",
            0u
        ) != std::string::npos
    );
}

Этот фрагмент, в чистом C ++ 98, открывает файл английских слов, сканирует каждое слово и печатает только слова длиной 8 с «a», «b», «c», «d», «e» или буквы 'f'.

Теперь включите C ++ 0X и лямбду:

#include <iterator>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>

int main()
{
 std::ifstream ifs("wordsEn.txt");
 std::copy_if(
    std::istream_iterator<std::string>(ifs),
    std::istream_iterator<std::string>(),
    std::ostream_iterator<std::string>(std::cout, "\n"),
    [](const std::string& s)
    {
       return (s.size() == 8 && 
               s.find_first_not_of("abcdef") == std::string::npos);
    }
 );
}

Это все еще немного тяжело для чтения (в основном из-за бизнеса istream_iterator), но намного проще, чем версия bind:)

18 голосов
/ 19 декабря 2009

Синтаксис C ++ 0x lamdba более читабелен, чем синтаксис bind. Как только вы получаете более 2-3 уровней привязки, ваш код становится в значительной степени нечитаемым и сложным в обслуживании. Я бы предпочел более интуитивный лямбда-синтаксис.

8 голосов
/ 19 декабря 2009

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

При связывании вы вынуждены создавать новую функцию / метод / функтор, даже если логика когда-либо нужна только в этом одном месте. Вам нужно придумать подходящее имя, и это может сделать код менее понятным, поскольку потенциально может привести к разделению связанной логики.

С помощью лямбды вы можете добавить новую логику внутри лямбды (но не обязаны, если есть смысл создавать новый вызываемый объект).

3 голосов
/ 19 декабря 2009

Я думаю, что это больше вопрос вкуса. Люди, которые быстро осваивают новые технологии или знакомы с функциональным программированием, вероятно, предпочтут лямбда-синтаксис, в то время как более консервативные программисты определенно предпочтут bind, поскольку он больше соответствует традиционному синтаксису C ++.

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

Что не меняет того факта, что лямбда-синтаксис гораздо более мощный и чистый.

1 голос
/ 24 декабря 2009

C ++ 0x лямбды по сути заменяют bind. Нет ничего, что вы могли бы связать, что вы не можете воссоздать тривиальную лямбду-обертку для достижения того же самого. std :: tr1 :: bind пойдет по пути std :: bind1st и т. д., как только будет широко распространена поддержка лямбды. Это хорошо, потому что по какой-то причине большинству программистов трудно связать свою голову.

...