dicroce
dicroce

Reputation: 46770

Why doesn't my function call match this generic functions implementation?

It seems like the compiler is very close to doing what I want (because it calls out my function as a candidate), but I have no idea what I'm doing wrong.

#include <stdio.h>
#include <stdlib.h>
#include <list>

using namespace std;

template <class U, template<class U> class T>
void AppendSorted( T<U>& l, U val )
{
  typename T<U>::reverse_iterator rt = l.rbegin();

  while( ((*rt) > val) && (rt != l.rend()) )
    rt++;

  l.insert( rt.base(), val );
}

int main( int argc, char* argv[] )
{
    list<int> foo;
    AppendSorted<int, list<int> >( foo, 5 );

    list<int>::iterator i;
    for( i = foo.begin(); i != foo.end(); i++ )
    {
        printf("%d\n",*i);
    }

    return 0;
}

The error I'm getting is:

test.cpp: In function ‘int main(int, char**)’:
test.cpp:21:43: error: no matching function for call to ‘AppendSorted(std::list<int>&, int)’
test.cpp:21:43: note: candidate is:
test.cpp:8:6: note: template<class U, template<class U> class T> void AppendSorted(T<U>&, U)

Upvotes: 1

Views: 124

Answers (3)

Leonid Volnitsky
Leonid Volnitsky

Reputation: 9144

std::list have actually two template parameters:

#include <stdio.h>
#include <stdlib.h>
#include <list>

using namespace std;

template <class U, template<class> class AL, template<class,class> class T> 
void AppendSorted( T<U,AL<U>>& l, U val ) {
        typename T<U,AL<U>>::reverse_iterator rt = l.rbegin();

        while( ((*rt) > val) && (rt != l.rend()) )
                rt++;

        l.insert( rt.base(), val );
}

int main( int argc, char* argv[] ) {
        list<int> foo;
        AppendSorted( foo, 5 ); 

        list<int>::iterator i; 
        for( i = foo.begin(); i != foo.end(); i++ ) {
                printf("%d\n",*i);
        }  

        return 0; 
}

Now it will compile, but you have logic error in your code - you have past-the-end iterator. To fix that, in you while loop, check for rend() first:

    while(rt != l.rend()  &&  *rt > val)

Upvotes: 1

PiotrNycz
PiotrNycz

Reputation: 24402

std::list is template taking two parameters - not only one. There is second default parameter.

You would need such template function to match list:

template <class U, template<class U,class A> class T>
void AppendSorted( T<U,std::allocator<T>>& l, U val );

But what about std::set - it requires 3 parameters?

I am not sure - maybe variadic templates would help...

But just try this:

template <class U, class Container>
void AppendSorted(  Container& l, U val);

Upvotes: 2

Ben Voigt
Ben Voigt

Reputation: 283634

This signature

template <class U, template<class U> class T>
void AppendSorted( T<U>& l, U val )

indicates that there will be one concrete type (class U) and one template (template<class U> class T).

This invocation

AppendSorted<int, list<int> >( foo, 5 );

provides two concrete types, int and list<int>. list is a template, list<int> is a concrete type, a template instance, but not a template.

Just change the function to accept the concrete type of the collection:

template <class U, class T>
void AppendSorted( T& l, U val )
{
  typename T::reverse_iterator /* or auto */ rt = l.rbegin();

  while( (rt != l.rend()) && ((*rt) > val) )
    rt++;

  l.insert( rt.base(), val );
}

And let the compiler infer the type arguments, instead of specifying them.

AppendSorted( foo, 5 );

Upvotes: 2

Related Questions