0

私は

using namespace std;
typedef vector<Coil*> CoilVec;
CoilVec Coils;

Coilの基本クラスでCilCoilありRectCoil、それぞれ円筒形コイルと長方形コイルです。ここで、指している incalcFieldごとにメンバー関数を呼び出したいと思います。このメンバー関数は、基本クラスでは純粋に仮想ですが、派生クラスで実装されており、その宣言は次のようになります。CoilCoils

virtual TVector3 calcField(const TVector3&);

Root ライブラリのTVector33D ベクター クラスです。Coilここでのアイデアは、すべてのフィールドを計算し、Coilsそれらを合計することです。(つまり、フィールドを計算する位置へのベクトル)の引数はcalcFieldすべての呼び出しで同じになるため、<algorithm>or<numeric>ヘッダーからSTLアルゴリズムを使用して、次のようなことをしたいと思います(想像):

using namespace std;
typedef vector<Coil*>::const_iterator CoilIt;
const TVector3& P(1.,1.,1.); // Let's say we want to know the total field in (1,1,1)
TVector3 B; // Default initialization: (0,0,0)
CoilIt begin = Coils.begin();
CoilIt end = Coils.end();
B = accumulate(begin, end, B, bind2nd(mem_fun(&Coil::calcField), P));

明らかに、私は質問をするためにここにいるので、これはうまくいかないようです。したがって、私の質問は非常に簡単に言えば、なぜこれが機能しないのか、および/または正しい方法で (STL の制限内で) どうすればよいのでしょうか?

上記をコンパイルしようとすると、次のエラー メッセージが表示されます (作業中のファイルは Interface.cpp と呼ばれ、サードパーティ コードです)。

In file included from /usr/include/c++/4.5/numeric:62:0,
                from Interface.cpp:7: /usr/include/c++/4.5/bits/stl_numeric.h: In function ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp, _BinaryOperation) [with _InputIterator = __gnu_cxx::__normal_iterator<Coil* const*, std::vector<Coil*> >, _Tp = TVector3, _BinaryOperation = std::binder2nd<std::mem_fun1_t<TVector3, Coil, const TVector3&> >]’:
Interface.cpp:289:72: instantiated from here
/usr/include/c++/4.5/bits/stl_numeric.h:150:2: error: no match for call to ‘(std::binder2nd<std::mem_fun1_t<TVector3, Coil, const TVector3&> >) (TVector3&, Coil* const&)’
/usr/include/c++/4.5/backward/binders.h:147:7: note: candidates are: typename _Operation::result_type std::binder2nd<_Operation>::operator()(const typename _Operation::first_argument_type&) const [with _Operation = std::mem_fun1_t<TVector3, Coil, const TVector3&>, typename _Operation::result_type = TVector3, typename _Operation::first_argument_type = Coil*]
/usr/include/c++/4.5/backward/binders.h:153:7: note:                  typename _Operation::result_type std::binder2nd<_Operation>::operator()(typename _Operation::first_argument_type&) const [with _Operation = std::mem_fun1_t<TVector3, Coil, const TVector3&>, typename _Operation::result_type = TVector3, typename _Operation::first_argument_type = Coil*]
4

4 に答える 4

0

呼び出しの結果は、bind2ndをとる単項関数ですColi*std::accumulateアキュムレータと現在の値で呼び出すことができるバイナリ関数を期待します。つまり、をとる関数が必要(TVector3, Coli*)です。

あなたがやろうとしていることは、それぞれColi*をaTVector3に変換してから、結果を蓄積することのようです。

これを明示的なstd::transform手順でavector<TVector3>に入力してから使用するか、を取り、を返すstd::accumulate別の無料関数を作成し、それを使用してバイナリアキュムレータ関数を取得することができます。(TVector3 t1, TVector3 t2, Coli* c)t2 + c->calcField(t1)bind1st

別の無料関数を記述せずにそれを実行したい場合は、boost::bindまたはC++11が必要になります。

于 2012-03-18T12:38:34.553 に答える
0

渡される関数std::accumulate()はバイナリ関数である必要があります。関数への各呼び出しには、2つのパラメーター(既に累積された値とベクトルの次の要素)が与えられます。

渡すバインドされた関数std::accumulate()は、1つのパラメーターaのみを取りますCoil*。と一緒に使用するaccumulateには、2つのパラメーター(Vector3DおよびCoil*)を使用する必要があります。

于 2012-03-18T12:34:26.030 に答える
0

必要なのは、ネストされたバインドです。非推奨のバインダーでこれらを行うのは非常に困難です。を使用した簡単な例を次に示しboost::bindます。

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
#include <boost/bind.hpp>

struct A {
  double foo(double d) { return d; }
};

int main()
{
  std::vector<A> vs;
  double d = 0.0;
  d = std::accumulate(begin(vs), end(vs), d, 
                      boost::bind(std::plus<double>(), _1, 
                                  boost::bind(boost::mem_fn(&A::foo), _2, 0.0)));
  return 0;
}

あなたの誤解は、あなた operator+が渡したファンクターの結果を累積するためにあなたが累積使用を想定していることだと思います。実際、ファンクターは結果を累積するために使用されます。foldこれは、関数型プログラミングにおける a の一般的な概念に基づいています。

渡すファンクタは次の形式でなければなりません

Ret func(const T1& a, const T2& b)

ここで、Ret は T (initパラメーターの型) に変換可能で なければならず、暗黙的に変換できるT1必要 があり、反復子をシーケンスに逆参照した結果が暗黙的に変換可能でなければなりません。TT2

于 2012-03-18T12:59:42.203 に答える
0

あなたのコードをや友人と一緒mem_funにコンパイルするのは、おそらく無駄なことです。bind2nd代わりに、古き良きループを書くことを強くお勧めします。

for (CoilIt it = coils.begin(); it != coils.end(); ++it)
{
    B += (**it).calcField(P);
}
于 2012-03-18T12:48:24.053 に答える