0

I'm using template functions in order that it may work with list or vector of different numerical data types. But one of them has an issue:

// This function should take 2 iterators of a vector/list and sum the elements between them
template <typename T >
double Sum1(typename T::const_iterator start, typename T::const_iterator end){
    double sum = 0;
    // For g++, "typename is needed before T::const_iterator"
    for(typename T::const_iterator I = start; I <= end;I++){
        sum += *I;
    }
    return sum;
}

in the main(), it is called like this:

vector<double> b;// and it is pushed by numbers 1-9 later

cout<<Sum1(b.begin(), b.end())<<endl;

but the compiler gives me errors

no matching function for call to ‘Sum1(std::vector::iterator, >std::vector::iterator)’

couldn't deduce template parameter ‘T’

However, this function works fine:

// T can be vector<int>, list<double>, etc. 
template <typename T >
double Sum(T& values){
    double sum = 0;
    // For g++, "typename is needed before T::const_iterator"
    for(typename T::const_iterator I = values.begin(); I != values.end();I++){
        sum += *I;
    }
    return sum;
}

Any idea why this happens? How should I revise the first function so it can take 2 iterators of a vector/list and calculate the sum in between?

Community
  • 1
  • 1
Partita
  • 205
  • 1
  • 2
  • 9

1 Answers1

4

Instead of templatizing on the container type, templateize on the iterator. And don't restrict your users to const_iterator -- any iterator should do is you don't actually modify the contents through the iterator:

template <typename Iter> double Sum1(Iter start, Iter end)

By doing this you can also use any type that is dereferenceable and incrementable -- such as a simple pointer.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • Yes I think you are right! It works fine with vector , but why doesn't it work with list? – Partita Aug 12 '14 at 13:52
  • 1
    @Partita `I <= end`does not work with list iterators, change that to `I != end` – Drax Aug 12 '14 at 13:58
  • 2
    Better yet, replace the function with `std::accumulate`. – chris Aug 12 '14 at 13:59
  • @Drax but it will neglect the last element. Here end is not b.end(), it could be any element's iterator – Partita Aug 12 '14 at 14:08
  • 1
    @Partita the whole iterator range concept in the STL works with a `[first, last)`range (meaning the last one is not included, and thus that you should always pass an iterator one step after the position of the last element you want to be processed), i highly advice you not to go against this design which is very natural to most c++ developers. But if you do, well you will have to add one more iteration after your loop, which is kinda ugly and is probably the main reason of this design in the STL in the first place :) – Drax Aug 12 '14 at 14:24
  • 1
    @Drax That's a really reasonable explanation. Thx! – Partita Aug 12 '14 at 14:41