2010-12-10 13 views
0

私はstd::vector<T>をクラスの一部であり、コード内のさまざまな場所で繰り返し処理する必要があるため、スマートにしてIterateAttributes関数を作成し、それをループ内のboost :: functionオブジェクトに渡して単一の要素を渡してから、要素を処理する関数を渡すことができます。メンバーを反復処理し、引数として渡された関数を呼び出す関数を呼び出す

これは実装するまでは良いアイデアだと思いますが、関数に渡されたものとは何かの問題があり、他の引数が必要です。テンプレートを使うような、より一般的なやり方を見つけなければならないか、あるいは異なるargを取る関数オブジェクトでオーバーロードを作成しなければならないようです。

私は最初の(より一般的な)オプションは多分良いと思いますが、どうすればいいでしょうか?

以下は、動作しない試行ですが、多数の引数を必要とし、属性(構造体)arg以外のすべての引数が必須である場合は試行されます。それについてどうすればいいですか?

template <typename T> template <typename arg> 
void ElementNode::IterateAttributes(boost::function<T (arg, Attribute)> func_) 
{ 
    std::vector<Attribute>::iterator it = v_attributes.begin(); 

    for (; it != v_attributes.end(); it++) 
    { 
     func_(arg, *it); 
    } 
} 
+0

あなたは 'boost :: bind'を使って最初に他の引数をバインドしてから' for_each'を使うことができます(本当に別の関数を書く必要がありますか?)。返り値を扱うにはもっと考えが必要です。 – lijie

+0

@lijie:for_eachは、反復処理中の要素を変更することを許可していないと思いましたか? –

+1

ええと...私はあなたが_collection_を変更するはずではないと思いますが、要素自体の変更を禁止するものはないと思います(特に要素の順序は関係ありません)。 – lijie

答えて

1

はあなたが何を意味するかということです:

任意の型のパラメータを1つだけできます
template <typename T, typename arg> 
void ElementNode::IterateAttributes(boost::function<T (arg, Attribute)> func_, arg a) 
{ 
    std::vector<Attribute>::iterator it = v_attributes.begin(); 

    for (; it != v_attributes.end(); it++) 
    { 
     func_(a, *it); 
    } 
} 

- あなたはより多くのパラメータについても、バージョンを導入することができますしたい場合。

戻り値について - それは実際にどのような価値があるかによって異なります - 一般的な(おそらくは不必要な)解決策はstd::list<T>を返すことですが、それは私が推測するよりも多くの問題を引き起こします。

迅速な回避策はあります
template <typename T> template <typename arg> 
void ElementNode::IterateAttributes(boost::function<voidT (arg, Attribute, T&)> func_) 
{ 
    std::vector<Attribute>::iterator it = v_attributes.begin(); 
    T result; 

    for (; it != v_attributes.end(); it++) 
    { 
     func_(arg, *it, result); 
    } 
    return result; 
} 

、それは動作しますが、それはです:戻り値の型が、その後(タイプではなく、意味だけでなく)が変化した場合、私はそれが全体的な結果と更新に応じて、それへの参照/ポインタを取るように、テンプレート機能をmodyfying示唆します醜い、エラーが発生しやすく、デバッグするのに苦労します。

あなたは可変パラメータ量をしたい場合は、あなたが上記の機能のいくつかのテンプレートを作成しなければならない - 私はちょうどテストそれが可能だとします。

template <typename T> 
T boo(T){ 

} 

template <typename T, typename TT> 
TT boo(T,TT){ 

} 

void test() 
{ 
    int i; 
    i= boo<int>(0); 
    i=boo<int,double>(0,0.0); 
} 

IterateAttributesに渡された関数がexatly与えられたパラメータと一致する必要があることを覚えておく必要があります関数を反復する。この場合には、a)あなたは、配列を反復処理し、そこに各要素に何かをしたい、おそらくあなたは

void func_(Attribute,arg1, arg2,arg3){...} 
void func_(Attribute A,arg1 a1,arg2 a2){func_(A,a1, a2,default3);} 
void func_(Attribute A,arg1 a1){func_(A,a1, default2,default3);} 
void func_(Attribute A){func_(A,default1, default2,default3);} 
+0

はい、それは私の言いたいことです。 1つは一般的なパラメータを持つことができますか?それともできないのですか? –

+0

とそれほど速い回避策はありますか? –

+0

"とそれほど速い回避策はありませんか?"あなたが完全に汎用的にしておきたいのであれば、テンプレートは結果が何であるかについて何も仮定することができないので、私が見る唯一の方法は結果リストを返すことです。そうでなければ、別の関数がパラメータとハングリングの結果として渡されたと考えるかもしれませんが、それはパラメータリストを拡大しており、原理的には上記の解とそれほど異なるものではありません。結果をどのようにしたいのかわからない場合は(テンプレートを書く段階で)、これを行う方法を言うことは不可能です。 –

0

のようないくつかのオーバーロードされたバージョンを定義する必要があります - それはまた、あなたがそれのプロトタイプのデフォルト値で使用することができないことを意味しますすべての配列要素を取り、voidを返す関数が必要です。シンプル。

b)各要素にさらに引数を指定して関数を部分的に適用したい場合は、事前に割り当てられた引数を格納するカスタム関数を書くか、boost::bindを使用します。

例:

vector<string> myStrings; // assign some values 

// define a function with an additional argument 
void myFunc(string message, string value) 
{ 
    cout << message << value << endl; 
} 

// allow partial application, i.e. "currying" 
struct local_function 
{ 
    static string message; 

    static void myFunc_Curried(string value) 
    { 
    myFunc(message, value); 
    }  
}; 

local_function::message = "the array contains: "; 

// apply the curried function on all elements in the array 
for_each(myStrings.begin(), myStrings.end(), local_function::myFunc_Curried); 

ファンクタはデモの目的のために静的に動作します。 messageが構造体のインスタンスにバインドされている場合は、実際にカリー化された関数を呼び出すために、などのインスタンスポインタthisをバインドする必要があります。ただし、適用したい機能がローカルでのみ使用されている場合、私はより読みやすい静的なアプローチに従うことをお勧めします。

あなたが達成しようとしていることは非常に意味があり、機能言語(F#など)にも直接組み込まれています。 C++で実現することは可能ですが、前述のケースではいくつかの回避策が必要です。私の例のように、あなた自身のファンクタを書く場合は、最初にカレーをはずしたい引数を配置し、部分的に適用するときには最初から最後まで引数を "埋める"ことが一般的であることに注意してください。

0

コメントやより多くの考えをまとめる:

後、得られ数子にfor_eachを使用し、他の引数をバインドするbindを使用してください。

戻り値を処理するには、戻り値の意味について考える必要があります。値を何らかの方法で使用する必要がある場合(たとえば、削減を実行する、または操作を実行するかどうかに影響を及ぼすなど)、別のファンクタを使用してオリジナルをラップして、必要なものを実行できます。

0

BOOST_FOREACHまたはC++ 0x for eachを使用しても同じことができます。それは書き込むコードが少なくて済みます。

関連する問題