2013-12-10 13 views
9

Se voglio calcolare la somma di una serie di numeri recuperati da un std::istream, posso effettuare le seguenti operazioni:eseguire due <algorithm> s fianco a fianco sullo stesso campo di ingresso iteratore

// std::istream & is = ... 
int total = std::accumulate(std::istream_iterator<int>(is), 
          std::istream_iterator<int>(), 
          0); 

Tuttavia, se vuole calcolare la loro media, ho bisogno di accumulare due risultati diversi:

  • la somma totale (std::accumulate)
  • il conteggio totale (std::distance)

C'è un modo per "unire" questi due algoritmi ed eseguirli "fianco a fianco" in una singola passata di un intervallo di iteratore? Mi piacerebbe fare qualcosa di simile:

using std::placeholders; 
int total, count; 
std::tie(total, count) = merge_somehow(std::istream_iterator<int>(is), 
             std::istream_iterator<int>(), 
             std::bind(std::accumulate, _1, _2, 0), 
             std::distance); 
double average = (double)total/count; 

è possibile?

risposta

11

Una soluzione pronta per questo tipo di accumulo a passaggio singolo è implementata da Boost.Accumulators. Fai un singolo accumulatore, dì per somma, conta e media, popola e poi estrai tutti e tre i risultati alla fine.

9

Non è possibile unire due diversi algoritmi per essere suddivise. Gli algoritmi controllano il flusso e puoi avere solo un flusso. Ora, nel vostro caso particolare è possibile simulare esso:

int count = 0; 
int total = std::accumulate(std::istream_iterator<int>(is), 
          std::istream_iterator<int>(), 
          0, 
          [&](int x, int y) { ++count; return x+y; }); 
-1

Questo è mod totale, ma qualcosa di simile:

#include <iostream> 
#include <algorithm> 
#include <tuple> 
#include <iterator> 
#include <sstream> 

namespace Custom { 
    template <class InputIterator, class T, class Bind, typename... Args> 
     std::tuple<Args...> accumulate (InputIterator first, InputIterator last, 
      T init, T& output, Bind bind, Args&... args) 
    { 
     while (first!=last) { 
     init = bind(init, *first, args...); 
     ++first; 
     } 
     output = init; 
     std::tuple<Args...> tuple(args...); 
     return tuple; 
    } 
} 

int main() { 
    int total = 0, count = 0; 
    std::istringstream is; 
    is.str("1 2 3 4 5"); 
    std::tie(count) = Custom::accumulate(std::istream_iterator<int>(is), 
     std::istream_iterator<int>(), 
     0, 
     total, 
     std::bind([&] (int a, int b, int& count) { ++count; return a + b; }, 
     std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), 
     count); 
    std::cout << total << " " << count; 
    return 0; 
} 
Problemi correlati