2009-03-06 7 views
7

Besoin d'une solution plus jolie de l'exemple ci-dessous mais avec std :: accumulate.en utilisant de std :: accumuler

#include <algorithm> 
#include <vector> 
#include <iostream> 

class Object 
{ 
public: 
    Object(double a, double b): 
     a_(a), 
     b_(b) 
    {} 

    double GetA() const { return a_; } 
    double GetB() const { return b_; } 
    // other methods 
private: 
    double a_; 
    double b_; 
}; 

class Calculator 
{ 
public: 
    Calculator(double& result): 
     result_(result) 
    {} 

    void operator() (const Object& object) 
    { 
     // some formula 
     result_ += object.GetA() * object.GetB(); 
    } 
private: 
    double& result_; 
}; 

int main() 
{ 
    std::vector<Object> collection; 
    collection.push_back(Object(1, 2)); 
    collection.push_back(Object(3, 4)); 

    double result = 0.0; 
    std::for_each(collection.begin(), collection.end(), 
        Calculator(result)); 

    std::cout << "result = " << result << std::endl; 

    return 0; 
} 
+0

Alors, pourquoi utilisez-vous std :: accumule pas? Quelle est exactement la question? – jalf

+0

@jalf: Bon point - Je me demande qu'est ce que mon code manque :) – dirkgently

+0

Acumulate retourne quoi? Je pensais qu'il retourne le même type qu'un objet, non? –

Répondre

11

faire des changements dans la calculatrice et la fonction principale.

struct Calculator 
{ 
    double operator() (double result, const Object& obj) 
    { 
     return result + (obj.GetA() * obj.GetB()); 
    } 

}; 

int main() 
{ 
    std::vector<Object> collection; 
    collection.push_back(Object(1, 2)); 
    collection.push_back(Object(3, 4)); 

    double result = std::accumulate(collection.begin(), collection.end(), 0, Calculator()); 
    std::cout << "result = " << result << std::endl; 

    return 0; 
} 

aussi pourrait être mieux:

double sumABProduct(double result, const Object& obj) 
{ 
    return result + (obj.GetA() * obj.GetB()); 
} 

double result = std::accumulate(collection.begin(), collection.end(), 0, sumABProduct); 
3

Mise à jour 2: Boost.Lambda fait un morceau de gâteau:

// headers 
#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 
using namespace boost::lambda; 
// ... 
cout << accumulate(dv.begin(), dv.end(), 
        0, 
        _1 += bind(&strange::value, _2)) //strange defined below 
    << endl; 

Mise à jour: Cela a été mise sur écoute-moi pendant un certain temps. Je ne peux pas obtenir n'importe lequel des algorithmes de STL pour fonctionner d'une manière décente. Donc, je roulais mon:

// include whatever ... 
using namespace std; 

// custom accumulator that computes a result of the 
// form: result += object.method(); 
// all other members same as that of std::accumulate 
template <class I, class V, class Fn1, class Fn2> 
V accumulate2(I first, I last, V val, Fn1 op, Fn2 memfn) { 
    for (; first != last; ++first) 
     val = op(val, memfn(*first)); 
    return val; 
} 

struct strange { 
    strange(int a, int b) : _a(a), _b(b) {} 
    int value() { return _a + 10 * _b; } 
    int _a, _b; 
}; 

int main() { 
    std::vector<strange> dv; 
    dv.push_back(strange(1, 3)); 
    dv.push_back(strange(4, 6)); 
    dv.push_back(strange(20, -11));   
    cout << accumulate2(dv.begin(), dv.end(), 
         0, std::plus<int>(), 
         mem_fun_ref(&strange::value)) << endl; 
} 

Bien sûr, la solution originale tient toujours: Le est de mettre en œuvre une operator+ plus facile. Dans ce cas:

double operator+(double v, Object const& x) { 
     return v + x.a_; 
} 

et en faire un ami de Object ou un membre (regarder pourquoi vous pouvez préférer un sur l'autre):

class Object 
{ 
    //... 
    friend double operator+(double v, Object const& x); 

et vous avez terminé avec:

result = accumulate(collection.begin(), collection.end(), 0.0); 

Mon approche précédente ne fonctionne pas car nous avons besoin d'un binary_function.

std::accumulate manuel.

+0

Merci pour le manuel. Mais votre code ne compilera pas. –

+0

"résultat" n'est pas initialisé. – MSalters

+0

Je pense que le troisième paramètre à accumuler devrait être 0 pas résultat. le résultat n'a pas encore été défini à ce moment-là. – Ferruccio

0

On espère que c'est des devoirs ...

struct Adapt { 
    static double mul(Object const &x) { return x.GetA() * x.GetB(); } 
    static double operator()(Object const &x, Object const &y) { 
     return mul(x)+mul(y); } }; 

et

result = std::accumulate(collection.begin(), collection.end(), Object(0,0),Adapt()); 

en supposant que vous n'êtes pas autorisé toucher la déclaration d'Objet.

+0

le résultat de l'accumulation devrait être «double» et non un «Adapt» –

1

est ici un problème ici, je suppose que les arguments sont écrits dans le mauvais ordre devrait être:

result = std::accumulate(collection.begin(), collection.end(), Object(0),Adapt()) 
where Adapt is defined thus: 

struct Adapt { 
    static double mul(Object const &x) { return x.GetA() * x.GetB(); } 
    static Object operator()(Object const &x, Object const &y) { 
     return Object(mul(x)+mul(y)) ; } }; 

dans ce cas de Accumulez, le résultat est contenu dans un objet retourné.

Si vous utilisez le mode parallèle gnu, le foncteur vous posera des problèmes si le résultat et l'objet réel référencés par l'itérateur sont différents.

struct Adapt { 
     static double mul(Object const &x) { return x.GetA() * x.GetB(); } 
     static double operator()(Object const &x, Object const &y) { 
      return mul(x)+mul(y) ; } }; 
result = std::accumulate(collection.begin(), collection.end(), 0.0,Adapt()) 

ne fonctionnera pas avec le mode parallèle GNU pour une raison étrange et stupide.

1

C++ 0x Utiliser:

#include <numeric> 
#include <vector> 
#include <iostream> 

class Object 
{ 
    public: 
    Object(double a, double b): 
     a_(a), 
     b_(b) 
     {} 

    double GetA() const { return a_; } 
    double GetB() const { return b_; } 
    // other methods 
    private: 
    double a_; 
    double b_; 
}; 

int main() 
{ 
    std::vector<Object> collection; 
    collection.push_back(Object(1, 2)); 
    collection.push_back(Object(3, 4)); 
    double result = std::accumulate(collection.begin(), collection.end(), 0, 
            [] (double result, const Object& obj) 
            { 
             return result + obj.GetA() * obj.GetB(); 
            } 
            ); 

    std::cout << "result = " << result << std::endl; 

    return 0; 
}