Если я хочу вычислить сумму группы чисел, полученных из std::istream
Я могу сделать следующее:
// std::istream & is = ...
int total = std::accumulate(std::istream_iterator<int>(is),
std::istream_iterator<int>(),
0);
Однако, если я хочу рассчитать их среднее значение, мне нужно получить два разных результата:
std::accumulate
)std::distance
)Есть ли способ «объединить» эти два алгоритма и запустить их «бок о бок» за один проход диапазона итераторов? Я хотел бы сделать что-то вроде:
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;
Это возможно?
Готовое решение для такого однопроходного накопления реализуется Boost.Accumulators. Вы делаете один аккумулятор, скажем, для суммы, подсчета и среднего, заполняете его, а затем извлекаете все три результата в конце.
Вы не можете объединить два разных алгоритма для чередования. Алгоритмы контролируют поток, и вы можете иметь только один поток. Теперь в вашем конкретном случае вы можете смоделировать это:
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; });
Это полный взлом, но что-то вроде этого:
#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;
}