14

どこにでもあるのではなく、C++11スタイルのラムダを使用するようにコードを移行することを考えていbindます。しかし、それが良い考えかどうかはわかりません。

eg boost::lambda(またはboost::phoenix)を使用すると、C ++ 11スタイルのラムダよりも実用的な利点がありますか?

ラムダに移行するのは良い考えですか?コードを移行する必要がありますか?

4

3 に答える 3

10

主な利点は、多相ファンクターです。現在、C++11 ラムダはモノモーフィックです。つまり、単一の引数型しか取りbind()ませんが、バインドされたファンクターが呼び出し可能である限り、任意の引数型を受け入れるファンクターを作成できます。

#include <functional>

struct X{
  template<class T, class U>
  void operator()(T, U) const{}
};

int main(){
  X x;
  auto l_with_5 = [x](int v){ return x(v, 5); };
  auto b_with_5 = std::bind(x, std::placeholders::_1, 5);
  l(4);
  b("hi"); // can't do that with C++11 lambdas
}
于 2012-08-21T20:49:14.927 に答える
7

はい、Boost ラムダはポリモーフィックですが、C++11 ラムダはそうではありません。つまり、たとえば、C++11 ラムダでは実行できません。

template<class T>
void f(T g)
{
    int x = 123;
    const char* y = "hello";
    g(x); // call with an integer
    g(y); // call with a string
}

int main() {
    f(std::cout << _1);
}
于 2012-08-21T20:50:49.403 に答える
3

はい:出力サイズに(場合によっては)大きな影響を与える可能性があります。

ラムダが何らかの形で互いに異なる場合、それらは異なるコードを生成し、コンパイラーは同じ部分をマージできない可能性があります。(インライン化により、これは非常に困難になります。)

これは、最初に見たときは、気付くまで大したことではないように見えます。のよう
なテンプレート関数内でそれらを使用すると、コンパイラは、異なるラムダごとstd::sortに新しいコード生成します。

これにより、コードサイズが不均衡に大きくなる可能性があります。

bindただし、通常は、このような変更に対してより回復力があります(ただし、変更の影響を受けません)。

私が何を意味するかを説明するために...

  1. 以下の例を見て、GCC(またはVisual C ++)でコンパイルし、出力バイナリサイズをメモします。
  2. に変更して、出力バイナリサイズがどのように変化if (false)したかを確認してください。if (true)
  3. 各部分のsの1つを除いてすべてコメントアウトした後、#1と#2を繰り返します。stable_sort

初めて、C++11ラムダがわずかに小さいことに注意してください。その後、使用するたびにサイズが大きくなります(VC ++ではソートごとに約3.3KBのコード、GCCと同様)が、ベースのバイナリはサイズをほとんど変更しません( 4つすべてboost::lambdaが同じサイズのままです)含まれる、最も近い0.5キロバイトまで)。

#include <algorithm>
#include <string>
#include <vector>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>   // can also use boost::phoenix

using namespace boost::lambda;

struct Foo { std::string w, x, y, z; };

int main()
{
    std::vector<Foo> v1;
    std::vector<size_t> v2;
    for (size_t j = 0; j < 5; j++) { v1.push_back(Foo()); }
    for (size_t j = 0; j < v1.size(); j++) { v2.push_back(j); }
    if (true)
    {
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::w, var(v1)[_1]) < bind(&Foo::w, var(v1)[_2]));
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::x, var(v1)[_1]) < bind(&Foo::x, var(v1)[_2]));
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::y, var(v1)[_1]) < bind(&Foo::y, var(v1)[_2]));
        std::stable_sort(v2.begin(), v2.end(), bind(&Foo::z, var(v1)[_1]) < bind(&Foo::z, var(v1)[_2]));
    }
    else
    {
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].w < v1[j].w; });
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].x < v1[j].x; });
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].y < v1[j].y; });
        std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].z < v1[j].z; });
    }
}

これは「スピードの取引サイズ」であることに注意してください。非常タイトなループにいる場合は、余分な変数が含まれる可能性があります(メンバーへのポインターを使用しているため)。
ただし、これはオーバーヘッドがもたらす(仮想呼び出しである)ようなものではなく、多くの場合それでも測定できないため、これが心配になることはありません。std::function

于 2012-08-21T20:38:43.520 に答える