4

I've managed to wrap my head around some of C++'s functional capacities (for_each, mapping functions, using iterators...) but the construction of the templates and function argument lists for taking in generic containers and iterators still eludes me. I have a practical example I'm hoping someone can illustrate for me:

Take the following function that processes an incoming std::vector and builds a running total of many data-points/iterations of a process:

/* the for-loop method - not very savvy */
void UpdateRunningTotal (int_vec& total, int_vec& data_point) {
  for (int i = 0; i < V_SIZE; i++) {
    total[i] += data_point[i];
  }
}

typedef int_vec std::vector<int>;
int_vec running_total (V_SIZE, 0);  // create a container to hold all the "data points" over many iterations
/* further initialization, and some elaborate loop to create data points */

UpdateRunningTotal (running_total, iteration_data);
/* further processing */

The above works, but I'd much rather have a function that takes iterators and performs this summation. Even better, have a generic parameter list with the type deduced instead of specifying the container type, i.e.:

UpdateRunningTotal (iteration_data.begin(), iteration_data.end(), running_total.begin());

I'm really lost at this point and need a little guidance to find how to define the template and argument lists to make the function generic. What would the template and function definition look like? I'm already familiar with a way to perform this specific task using STL functionality - I'm looking for illustration of the generic function/template definition.

Shamster
  • 2,092
  • 5
  • 24
  • 27

2 Answers2

7

You could use std::transform and std::plus:

std::transform(iteration_data.begin(), iteration_data.end(),
                running_total.begin(), iteration_data.begin(), std::plus<int>());

And in your function, that would be:

template <typename Iter1, typename Iter2>
void UpdateRunningTotal(Iter1 pBegin, Iter1 pEnd, Iter2 pBegin2)
{
    typedef typename std::iterator_traits<Iter1>::value_type value_type;

    std::transform(pBegin, pEnd, pBegin2, pBegin, std::plus<value_type>());
}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • Because the Iter1 and Iter2 type aren't specified, they must be deduced. Is the deduction happening in the function body (i.e. at the typedef)? Or am I missing something fundamental where iterators don't need to have template parameters specified? – Shamster Jun 07 '10 at 17:49
  • It's exactly the same is if your template were taking ints or floats. It's just that in this case, it's taking something more like `vector::iterator`. – Jonathan M Davis Jun 07 '10 at 17:53
  • 2
    @Shamster: So, what `UpdateRunningTotal` is (in my code) is a "function template". Keeping in mind we call functions and not function templates, when we call `UpdateRunningTotal` it needs to be "instantiated" resulting in a function we will actually call. In order to instantiate a template, all the template parameters must be provided. Now, you could do: `UpdateRunningTotal(/* ... */)` and fill them in yourself, but that's ridiculous. Rather, function templates will "deduce" their template parameters from the function parameters. When we call it, in order to instantiate a function it... – GManNickG Jun 07 '10 at 17:55
  • 2
    ...will deduce that we should have `Iter1` be the type of `pBegin`, and `Iter2` should be the type of `pBegin2`, and will implicitly fill in those template parameters. That's all of them, so the function is instantiated. (So in the body of the function, the types of `Iter1` and `Iter2` are already known.) – GManNickG Jun 07 '10 at 17:56
  • @GMan: Is the type deduction specific to iterator arguments, or can other types be deduced as well? If such is the case, why is the typedef used? Couldn't the `std::plus()` deduce the `value_type` without the explicit definition just based on the already-deduced types of the `Iter` arguments? – Shamster Jun 07 '10 at 18:04
  • std::plus is a class template and class templates are never deduced. – Edward Strange Jun 07 '10 at 18:06
  • @Shamster: The last argument to `transform` needs to be a type, `std::plus` is not a type, it's a "class template". Instantiate that class template (by providing the necessary template parameters) to get a class type. `std::plus` *could* have been written this way: `struct plus { template T operator()(const T& pX, constT& pY) { return pX + pY; } };`, but all that's doing is moving the deduction to the call to `operator()`, which has trade-offs. I'd recommend a book, which would explain this much better. http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – GManNickG Jun 07 '10 at 18:11
1

Well, I could give you a function signature that you'll have to fill with correct implementation since your specification isn't making sense to me right now.


template < typename InputIterator, typename OutputIterator >
?? UpdateRunningTotal(InputIterator beg, InputIterator end, OutputIterator dest)
{
}
Edward Strange
  • 40,307
  • 7
  • 73
  • 125