David
David

Reputation: 1

Template signature problem

I am new to using templates and am required to use a template to do something, but don't know how to call the templated function. It's probably soething simple, but I can't see it.

template<class It, class T>


// iterator and value_type of *It
void Calc(It begin, It end, std::pair<int, int> &out)
{
        std::vector<It>::iterator iter;
    std::map<int, int> StartMap;
    std::map<int, int>::reverse_iterator rit;

    int sum, start, stop, count;
    start = stop = 1;
    count = sum = 0;

    for(iter = begin; iter != end; iter++ )
    {
        sum += iter;
        count++;
        stop++;
        if(sum <= 0)
        {
            // store original start
            StartMap.insert(start, count);
            // set new start position
            start = stop;
        }   
    }

    // set iterator to highest value
    rit = StartMap.rbegin();

    start = rit->first;
    stop = start + rit->second;

    out.insert(start, stop);
}

but not sure how I call it with 2 std::vector iterators. I've tried this

void doSomething(std::vector<int>& stopsVec)
{
    std::pair<int, int> out;
    Calc<std::vector<int>::iterator, std::pair<int, int>>(stopsVec.begin(), stopsVec.end(), &out);
}

Upvotes: 0

Views: 268

Answers (3)

templatetypedef
templatetypedef

Reputation: 373172

You don't need to explicitly pass the type being iterated over as a template argument. The STL designers were quite wise and realized that this often comes up, and there's a (not very pretty but entirely correct) way to introspect on the type of an iterator to get it's underlying type as follows:

typedef typename std::iterator_traits<It>::value_type value_type;

Once you've done this, you can use the name value_type to refer to the type being iterated over. This lets you rewrite the template function as

template <typename It>
void Calc(It begin, It end, std::pair<int, int>& out) {
     typedef typename std::iterator_traits<It>::value_type value_type;
     /* ... Rest of the code, now using this type ... */
}

And to seal the deal, now that there aren't any auxiliary types required, you can call the function directly as

std::vector<int> v = /* ... */
std::pair<int, int> result;
Calc(v.begin(), v.end(), result);

Hopefully this is easier to read and write!

Upvotes: 0

Tim
Tim

Reputation: 9172

void doSomething(std::vector<int>& stopsVec)
{
    std::pair<int, int> out;
    Calc<std::vector<int>::iterator, std::pair<int, int> >
        (stopsVec.begin(), stopsVec.end(), out);   // not &out
}

Calc takes a reference to std::pair<int, int>, so you want to just give it out. Passing &out tries to pass a pointer to a pair - which won't work.

EDIT

assuming the signature is actually:

template<class It>
void Calc(It begin, It end, std::pair<int, int> &out)

You can call it with:

Calc(stopsVec.begin(), stopsVec.end(), out);

The compiler can deduce the correct template type from the parameters, without requiring you to specify them between <>

EDIT

Keith makes a good point below. That's another compilation error you would have here. Also note that:

sum += iter;

does not do what you want. you probably meant:

sum += *iter;

But since sum is an int, and iter is a template type, this is not really a general-purpose template method. It's really only going to work for iterators over numeric types.

And, one other issue:

Calc<std::vector<int>::iterator, std::pair<int, int> >  // use a space
    (stopsVec.begin(), stopsVec.end(), out);

instead of

Calc<std::vector<int>::iterator, std::pair<int, int>>  // ">>" is shift operator
    (stopsVec.begin(), stopsVec.end(), out);

You need a space between the closing > signs in order to have template syntax. Otherwise you're doing bitshift (or stream extraction), and the compiler will get confused because nothing will make sense from that point on.

Upvotes: 4

Keith
Keith

Reputation: 6834

Note that:

template<class It, class T>
void Calc(It begin, It end, std::pair<int, int> &out)
{
    std::vector<It>::iterator iter;
    for(iter = begin; iter != end; iter++ )

is wrong. It should probably be:

template<class It, class T>
    void Calc(It begin, It end, std::pair<int, int> &out)
    {
        It iter;
        // etc.
        for(iter = begin; iter != end; iter++ )

But also note that in C++, it is generally preferred to follow the 'declaration is initialisation' approach, so this becomes:

  template<class It, class T>
        void Calc(It begin, It end, std::pair<int, int> &out)
        {
             // etc.
            for(It iter = begin; iter != end; iter++ )

Upvotes: 0

Related Questions