views:

86

answers:

2

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.

+6  A: 

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>());
}
GMan
+1: I was about to suggest a similar approach.
Alerty
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
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<int>::iterator`.
Jonathan M Davis
@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<X, Y>(/* ... */)` 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...
GMan
...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.)
GMan
@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
std::plus is a class template and class templates are never deduced.
Noah Roberts
@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 <typename T> T operator()(const T } };`, 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
GMan
+1  A: 

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)
{
}
Noah Roberts