2012-03-18 3 views
0

У меня естьВызов функции-члена с одним параметром (связан) для каждого объекта в контейнере

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

с Coil быть базовым классом для CilCoil и RectCoil, A cilindrical катушки и прямоугольной катушки, соответственно. Теперь я хочу вызвать функцию-член calcField на каждом Coil, указанном в Coils. Эта функция члена чисто виртуальная в базовом классе, но была реализована в производных классов, и его заявление выглядит следующим образом:

virtual TVector3 calcField(const TVector3&); 

с TVector3 быть вектор класса 3D из библиотеки ROOT. Идея теперь состоит в том, чтобы вычислить поле каждого Coil в Coils и добавить их вместе. Поскольку аргумент calcField (а именно вектор для позиции для вычисления поля) будет одинаковым для каждого вызова, я хотел бы использовать алгоритм STL из заголовка <algorithm> или <numeric>, чтобы сделать что-то вроде этого (воображаемого):

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*] 
+0

Не собирайтесь давать это как ответ, поскольку вы просили что-то в STL, но считали ли вы библиотеки Boost (в частности boost :: bind)? У меня была такая же проблема, как и исправление. – chameco

+0

Похоже, вы хотите 'for_each', а не' накапливать'. – interjay

+0

'Катушки' - это тип, а не объект, поэтому' Coils.begin() 'не имеет смысла. – fredoverflow

ответ

0

функция перешла к std::accumulate() должен быть бинарной функцией, каждому вызову функции будут заданы два параметра (уже накопленное значение и следующий элемент вектора).

Связанная функция, которую вы передаете std::accumulate(), принимает только один параметр, Coil*. Для использования с accumulate потребуется два параметра (Vector3D и Coil*).

0

Результат вашего звонка bind2nd является унарной функцией, которая принимает Coli*. std::accumulate ожидает двоичную функцию, которая может быть вызвана с аккумулятором и текущим значением, то есть ему нужна функция, которая принимает (TVector3, Coli*).

Кажется, что вы пытаетесь преобразовать каждый Coli* в TVector3, а затем аккумулировать результаты.

Вы можете сделать это с явным std::transform шаг, чтобы заполнить vector<TVector3>, а затем использовать std::accumulate, или вы могли бы написать отдельную свободную функцию, которая принимает (TVector3 t1, TVector3 t2, Coli* c), возвращает t2 + c->calcField(t1), а затем использовать bind1st на то, чтобы получить бинарную функцию аккумулятора.

Если вы хотите сделать это без написания отдельной бесплатной функции, вам понадобится boost::bind или C++ 11.

+0

Это действительно компилируется! Мне еще нужно запустить некоторые тесты, чтобы проверить, делает ли он то, что я хочу, но я надеюсь ... – Wouter

0

Возможно, не стоит пытаться скомпилировать ваш код с помощью mem_fun, bind2nd и друзей.Я бы настоятельно рекомендовал вместо этого написать хорошую старомодную петлю:

for (CoilIt it = coils.begin(); it != coils.end(); ++it) 
{ 
    B += (**it).calcField(P); 
} 
+0

Это, вероятно, будет моим временным решением, пока я не углубится в boost. Тем не менее, я бы хотел избежать циклов, даже если они кажутся приемлемыми. – Wouter

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 в функциональном программировании.

Функтора вы передаете должен иметь вид

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

, где Сход должен быть конвертирован в T (типа параметра init), T1 должны быть такими, что T может быть неявно преобразован в него и T2 должны быть такими, чтобы результат разыменования итератора в последовательность должен быть неявно конвертирован в него.

+0

Мне нужно будет кое-что научиться, чтобы действительно понять это. Мы должны взглянуть на библиотеку boost на моем курсе C++ во вторник. Надеюсь, это поможет прояснить ситуацию. Но, как я сказал в комментарии к моему вопросу: я надеялся, что решение STL возможно, по крайней мере на данный момент. – Wouter

+0

@Wouter C++ 11 имеет 'std :: bind', который является стандартизированной версией' boost :: bind'. Код выше должен быть почти на 100% совместим с ним. Если у вас есть недавний компилятор, пойдите с ним. Опять же, вы, вероятно, будете использовать lamdba для этого с недавним компилятором. – pmr

 Смежные вопросы

  • Нет связанных вопросов^_^