2011-11-03 9 views
5

lambdaを使用して複雑さを大幅に軽減できるコードがいくつかあります。しかし残念ながら、C++ 11を完全にサポートしていないコンパイラを使用する必要があり、簡単に切り替えることはできません。今問題は、利用可能な機能がないラムダ式にできるだけ近いロジックを維持する方法です(つまり、std::functionが利用可能で、ラムダは使用できません)。lambdaをpre-lambdaコンパイラで処理する方法

通常の解決策はどこかファンクタを定義し、適切な場所でそれを使用することです:

struct functor{ 
    functor(type & member) : m_member(member) {} 
    void operator()(...) {...} 
    type & m_member; 
}; 

void function() { 
    use_functor(functor(...)); 
} 

私はそれをたくさん嫌いが、私は、非常にこのパターンを使用しています。クラスを定義しない主な理由は、通常、ファンクタはSTL内で使用され、テンプレートは関数のインラインで定義された構造体が好きではないということです。しかし、私の場合、use_functor()関数は通常の方法になるので、関数自体の中で関数を定義することができます(各関数は1つの関数内でのみ使用されます)。

void function() { 
    struct functor{ 
     functor(type & member) : m_member(member) {} 
     void operator()(...) {...} 
     type & m_member; 
    }; 
    use_functor(functor(...)); 
} 

これはやや改善されているようですが、私が望むより醜いコードが必要です。たとえば、私はファンクタの名前を完全に取り除きたいと思います。私はそれが唯一の値を使用する場合、匿名の構造体を作成することは可能です知っている。

void function() { 
    struct{ 
     // functor(type member) : m_member(member) {} 
     void operator()(...) {...} 
     // type & m_member; 
    } callback ; 
    use_functor(callback); 
} 

は、しかし、この時点で私は、必要なデータメンバを提供する方法について見当もつかない。構造体は匿名であるため、コンストラクタはありません。私は簡単にメンバーを設定することができます。なぜなら、メンバーは一般公開されているからですが、これもまた私が嫌う行を追加することになります。

目標は、この問題を完全に排除することができるクリーンラムダを持つコンパイラに切り替えた後、できるだけ変更する必要がない状態にしておくことです。

どうやってこれをやりますか? callbacktype &参照m_memberを設定する

void function() { 
    type the_thing; 
    struct { 
     void operator()(...) {...} 
     type & m_member; 
    } callback = {the_thing}; 
    use_functor(callback); 
} 

:あなたが行うことができますコンストラクタのない匿名structのメンバ変数のinitalisationに関して

+0

古いGCCの中には、関数内でネストされた構造体からstd :: function <>への変換を処理しないものもあります。だから私はオプション1を使用してロジックを分離することを余儀なくされています。 – LiKao

答えて

1

。 awoodlandによって答えに拡大

0

#define MY_LAMBDA(name, memberType, memberValue, body) \ 
    struct {          \ 
     void operator()(...) body    \ 
     memberType & memberValue;     \ 
    } name = {memberValue} 

void function() { 
    type thing_to_capture; 

    MY_LAMBDA(callback, type, thing_to_capture 
    { 
     std::cout << thing_to_capture << std::endl; 
    }); 

    use_functor(callback); 
} 

あなたはどこでもあなたが構造体を定義することができますMY_LAMBDAを使用することができます。残念ながら、バリデージックマクロを使用しない場合は、キャプチャしたすべてのオブジェクトを1つのオブジェクトにラップする必要があります。そのオブジェクトのタイプを「ラムダ宣言」で指定する必要があります。

ラムダを使用する同等のものは

void function() { 
    type thing_to_capture; 

    auto callback = [&thing_to_capture]() 
    { 
     std::cout << thing_to_capture << std::endl; 
    }; 

    use_functor(callback); 
} 
+0

タイプミスの可能性を排除するために、マクロの先頭に 'type thing_to_capture;'を追加することができます(この例のように、明示的なc'torまたはcopy-assigningを呼び出さない場合)。 – Richard

+1

'MY_LAMBDA'は' operator() 'の定義を指定できないとどのように役立ちますか? – ildjarn

+0

@ildjarn良い点...今後の予定です。 –

0

ブーストラムダライブラリーまたはboost::phoenixを試すことができます。それらは両方とも実際のラムダサポートなしでラムダスタイルの操作を行うように設計されています。テンプレートベースなので、何かが期待どおりに動作しないときにエラーをデバッグするのは難しいでしょう。

関連する問題