C++ 0xのstd :: bindとlambdaのどちらのスタイルが好ましいかについて質問があります。私はそれらが何らかの形で異なる目的を果たしていることを知っていますが、交差する機能の例を取り上げましょう。
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);
どっちがいい?どうして?前述の例と比較して、より複雑な状況を想定しています。つまり、一方の利点と他方の欠点は何ですか。
あなたが言ったように、バインドとラムダはまったく同じ目標を目指していません。
たとえば、STLアルゴリズムを使用および構成する場合、ラムダは明らかに勝者です、IMHO。
説明のために、私はスタックオーバーフローで非常に面白い答えを覚えています。ここでは、誰かが16進数のマジックナンバー(0xDEADBEEF、0xCAFEBABE、0xDEADDEADなど)のアイデアを求め、彼が本当のC++プログラマーであれば、単にそうするだろうと言われました。英語の単語のリストをダウンロードし、C++のシンプルな1行を使用します:)
#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で英語の単語ファイルを開き、各単語をスキャンして、「a」、「b」、「c」、「d」、「e」、または「f」を含む長さ8の単語のみを印刷します。手紙。
次に、C++ 0Xとlambdaをオンにします。
#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ビジネスのため)、バインドバージョンよりもずっと単純です:)
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はnotで固定されていることに注意してください。 fが実際に使用された場合のみ、これら2つが推定されます。
C++ 0x lamdba構文は、バインド構文よりも読みやすくなっています。 2〜3レベルのバインドに入ると、コードはほとんど読めなくなり、保守が困難になります。私はより直感的なラムダ構文を好みます。
ラムダの利点の1つは、既存の関数の上に少し大きなロジックを追加する必要がある場合に、より便利になることです。
Bindを使用すると、ロジックがこの1か所でのみ必要になる場合でも、新しい関数/メソッド/ファンクターを作成する必要があります。適切な名前を付ける必要があります。関連するロジックを分割する可能性があるため、コードがわかりにくくなる可能性があります。
ラムダを使用すると、ラムダ内に新しいロジックを追加できます(ただし、新しい呼び出し可能オブジェクトを作成することが理にかなっている場合は強制されません)。
もっと味の問題だと思います。新しいテクノロジーをすぐに理解する人、または関数型プログラミングに精通している人はおそらくラムダ構文を好むでしょう。一方、より保守的なプログラマーは、従来のC++構文に近いため、間違いなくバインドを好みます。
そのような決定は、おそらく過半数の投票を通じて、コードを扱う人々と協力して行われるべきです。
しかし、それでも事実は変わりませんが、ラムダ構文の方がはるかに強力でクリーンです。
C++ 0xラムダは本質的にバインドを置き換えます。同じことを達成するために些細なラッパーラムダを再作成できないことをバインドできるものはありません。 std :: tr1 :: bindは、ラムダサポートが広く普及すると、std :: bind1stのように進みます。なんらかの理由で、ほとんどのプログラマーはバインドに頭を悩ませるのに苦労するので、これは良いことです。