Vincular Vs Lambda?

Eu tenho uma pergunta sobre qual estilo é preferido: std :: bind Vs lambda em C ++ 0x. Eu sei que eles servem, de alguma forma, diferentes propósitos, mas vamos dar um exemplo da funcionalidade de interseção.

Usando lambda :

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

Usando bind :

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

Qual devemos preferir? porque? assumindo situações mais complexas em relação ao exemplo mencionado. ou seja, quais são as vantagens / desvantagens de uma sobre a outra?

Como você disse, bind e lambdas não visam exatamente o mesmo objective.

Por exemplo, para usar e compor algoritmos de STL, os lambdas são vencedores claros, IMHO.

Para ilustrar, eu me lembro de uma resposta muito engraçada, aqui no estouro de pilha, onde alguém pediu idéias de números mágicos hexadecimais (como 0xDEADBEEF, 0xCAFEBABE, 0xDEADDEAD etc.) e foi dito que se ele fosse um programador C ++ real ele simplesmente teria faça o download de uma lista de palavras em inglês e use um simples one-liner de C ++ 🙂

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

Este trecho, em puro C ++ 98, abre o arquivo de palavras em inglês, escaneia cada palavra e imprime somente aquelas de comprimento 8 com ‘a’, ‘b’, ‘c’, ‘d’, ‘e’ ou ‘f’ cartas.

Agora, ative C ++ 0X e lambda:

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

Isso ainda é um pouco pesado para ler (principalmente por causa do negócio do istream_iterator), mas muito mais simples que a versão do bind 🙂

Os lambdas do C ++ 0x são monomórficos, enquanto o bind pode ser polimórfico. Você não pode ter algo como

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

a e b devem ter tipos conhecidos. Por outro lado, tr1 / boost / phoenix / lambda bind permite que você faça isso:

 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" 

Observe que os tipos A e B não estão corrigidos aqui. Somente quando f é realmente usado, esses dois serão deduzidos.

A syntax C ++ 0x lamdba é mais legível que a syntax de vinculação. Uma vez que você entrar em mais de 2-3 níveis de vinculação, o código se torna praticamente ilegível e de difícil manutenção. Eu preferiria a syntax lambda mais intuitiva.

Um dos benefícios dos lambdas é que eles são muito mais úteis quando você precisa adicionar um pouco de lógica sobre uma function existente.

Com bind, você é forçado a criar uma nova function / método / functor mesmo se a lógica só for necessária neste único lugar. Você precisa criar um nome apropriado e isso pode tornar o código menos compreensível, já que potencialmente faz com que você divida a lógica relacionada.

Com lambda, você pode adicionar a nova lógica dentro do lambda (mas não é forçada a fazer sentido criar um novo callable).

Eu acho que é mais uma questão de gosto. Pessoas que captam rapidamente novas tecnologias, ou que estão familiarizadas com a functional programming, provavelmente preferirão a syntax lambda, enquanto programadores mais conservadores irão definitivamente preferir bind, já que é mais parecida com a syntax tradicional do C ++.

Essa decisão deve ser tomada em coordenação com as pessoas que trabalharão com o código, provavelmente por meio de uma votação majoritária.

O que não muda o fato, no entanto, que a syntax lambda é muito mais poderosa e mais limpa.

C ++ 0x lambdas essencialmente substituem a binding. Não há nada que você possa ligar que você não pode recriar um lambda wrapper trivial para conseguir o mesmo. std :: tr1 :: bind seguirá o caminho de std :: bind1st, etc, uma vez que o suporte a lambda é muito difundido. O que é bom, porque, por alguma razão, a maioria dos programadores tem dificuldade em se concentrar no bind.