trouble when overloading function used as predicate in std::sort

H

hall

I accidently overloaded a static member function that I use as predicate
in the std::sort() for a vector and ended up with a compiler error. Is
this kind of overload not allowed for predicates and if so, why not?
Shouldn the compiler be able to tell which of he overloaded functions to
use?

The second A::comp() is the one I accidently added and gives the error
message (in Borland C++Builder 6)

[C++ Error] Unit1.cpp E2285 Could not find a match for
'sort<_RandomAccesIter, _Compare>(A*,A*,bool(*)(const A&,const A&))'

Commenting out the line makes the code compile just fine.

//---------------------------------------------------------------------------
#include <vector>
#include <algorithm>

using namespace std;

struct A {
int a;
A(int a0): a(a0) {}
static bool comp ( const A a1, const A & a2) {return a1.a<a2.a;}
static bool comp ( const A a1 ){ return true; } //< causes
compiler error
};

int main(int argc, char* argv[])
{
vector<A> a;
a.push_back(A(4));
a.push_back(A(7));
sort( a.begin(), a.end(), A::comp );

return 0;
}
//---------------------------------------------------------------------------
 
R

Robbie Hatley

hall said:
I accidently overloaded a static member function that I use as predicate
in the std::sort() for a vector and ended up with a compiler error. Is
this kind of overload not allowed for predicates and if so, why not?
Shouldn the compiler be able to tell which of he overloaded functions to
use?

The second A::comp() is the one I accidently added and gives the error
message (in Borland C++Builder 6)

[C++ Error] Unit1.cpp E2285 Could not find a match for
'sort<_RandomAccesIter, _Compare>(A*,A*,bool(*)(const A&,const A&))'

Commenting out the line makes the code compile just fine.

//---------------------------------------------------------------------------
#include <vector>
#include <algorithm>

using namespace std;

struct A {
int a;
A(int a0): a(a0) {}
static bool comp ( const A a1, const A & a2) {return a1.a<a2.a;}
static bool comp ( const A a1 ){ return true; } //< causes
compiler error
};

int main(int argc, char* argv[])
{
vector<A> a;
a.push_back(A(4));
a.push_back(A(7));
sort( a.begin(), a.end(), A::comp );

return 0;
}

Well, one thing that bothers me is that sort() expects the
predicate to have argument signature:

(const A&, const A&)

but you use:

(const A , const A&)

Forget the '&'?

That may not be related to your problem, but it's
an error you should look into.

I did try compiling your program on DJGPP (a port of the
Gnu C++ compiler to Windows-command-prompt environment,
from www.delorie.com ). I got this:

wd=C:\C\test
%make predicate-test
gpp -IC:/C/lib -pedantic -Wall -W -Wshadow -Wcast-qual -Wcast-align -Wconversion
-Os -s -LC:/C/lib predicate-test.cpp -lrh -lm -o C:/Software/predicate-test.exe

predicate-test.cpp: In function `int main()':
predicate-test.cpp:19: error: no matching function for call to `sort(
__gnu_cxx::__normal_iterator<A*, std::vector<A, std::allocator<A> > >,
__gnu_cxx::__normal_iterator<A*, std::vector<A, std::allocator<A> > >,
<unknown type>)'
make.exe: *** [predicate-test] Error 1

But when I comment-out the extra version of comp, it compiles fine.

I get the same results if I take the comp's out of the class and
make them global functions. I even changed the extra comp to
a totally unrelated signature:

double comp (int a, char b)
{
return a + b;
}

But any way I try it, the extra comp apparently causes
the compiler to see "comp" in your call to sort() as being
an "unknown type".

Perhaps the problem is related to the fact that the name "comp"
is a pointer to a function. Perhaps sort() can't check signatures
and relies on an unambiguous pointer-to-function called "comp",
which would preclude overloading.


--
Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
 
H

hall

Robbie said:
I accidently overloaded a static member function that I use as predicate
in the std::sort() for a vector and ended up with a compiler error. Is
this kind of overload not allowed for predicates and if so, why not?
Shouldn the compiler be able to tell which of he overloaded functions to
use?

The second A::comp() is the one I accidently added and gives the error
message (in Borland C++Builder 6)

[C++ Error] Unit1.cpp E2285 Could not find a match for
'sort<_RandomAccesIter, _Compare>(A*,A*,bool(*)(const A&,const A&))'

Commenting out the line makes the code compile just fine.

//---------------------------------------------------------------------------
#include <vector>
#include <algorithm>

using namespace std;

struct A {
int a;
A(int a0): a(a0) {}
static bool comp ( const A a1, const A & a2) {return a1.a<a2.a;}
static bool comp ( const A a1 ){ return true; } //< causes
compiler error
};

int main(int argc, char* argv[])
{
vector<A> a;
a.push_back(A(4));
a.push_back(A(7));
sort( a.begin(), a.end(), A::comp );

return 0;
}


Well, one thing that bothers me is that sort() expects the
predicate to have argument signature:

(const A&, const A&)

but you use:

(const A , const A&)

Forget the '&'?

Ah, yes, the & apperantly got lost when I wrote the example. However it
was (const A& , const A&) in the piece of code where the problem first
occured.
That may not be related to your problem, but it's
an error you should look into.

I did try compiling your program on DJGPP (a port of the
Gnu C++ compiler to Windows-command-prompt environment,
from www.delorie.com ). I got this:

wd=C:\C\test
%make predicate-test
gpp -IC:/C/lib -pedantic -Wall -W -Wshadow -Wcast-qual -Wcast-align -Wconversion
-Os -s -LC:/C/lib predicate-test.cpp -lrh -lm -o C:/Software/predicate-test.exe

predicate-test.cpp: In function `int main()':
predicate-test.cpp:19: error: no matching function for call to `sort(
__gnu_cxx::__normal_iterator<A*, std::vector<A, std::allocator<A> > >,
__gnu_cxx::__normal_iterator<A*, std::vector<A, std::allocator<A> > >,
<unknown type>)'
make.exe: *** [predicate-test] Error 1

But when I comment-out the extra version of comp, it compiles fine.

I get the same results if I take the comp's out of the class and
make them global functions. I even changed the extra comp to
a totally unrelated signature:

double comp (int a, char b)
{
return a + b;
}

But any way I try it, the extra comp apparently causes
the compiler to see "comp" in your call to sort() as being
an "unknown type".

Perhaps the problem is related to the fact that the name "comp"
is a pointer to a function. Perhaps sort() can't check signatures
and relies on an unambiguous pointer-to-function called "comp",
which would preclude overloading.

Yes, so it seems. I am interested to find out more precisly why the
compiler cannot tell which version of comp to use. As the compiler error
messages in this case didn't help much (at least not me), it would be
good to know if this problem may occur somwhere else.

I made a small test for the pointer theory:

//------------------------------------------------------------------------
#include <string>
#include <iostream>
using namespace std;

void fun (int &i){ cout << "fun(int&): "<<i; }
void fun (string s) {cout << "fun(string&): "<<s;}
foo( void (*f)(int&)){ f(1); }

int main(int argc, char* argv[])
{
foo(fun);
return 0;
}
//---------------------------------------------------------------------------


This will compile and correctly run fun(int&), so here the compiler
seems to know which of the overloaded fun() to use. Now, pointers to
functions aren't someting i'm good at, so this may not be an equivalent
case to the original problem with std::sort(). But then what is the
difference? The fact that sort is templatized?

Any comments are appreachiated.

regards
hall
 
J

John Harrison

Yes, so it seems. I am interested to find out more precisly why the
compiler cannot tell which version of comp to use. As the compiler error
messages in this case didn't help much (at least not me), it would be
good to know if this problem may occur somwhere else.

You are confusing two different processes. The first process is template
argument deduction. std::sort has a definition something like this

template <class I, class F>
void sort(I first, I last, F comp)
{
...
}

and when you call std::sort the compiler attempt to match the types you
supply with the types in the template. Now here's the rub, sort is defined
with a third parameter F, *anything* will match this parameter, literally
anything, int, string, bool, you name it. Obviously in this situation the
compiler cannot decide between your two versions of comp because they both
match. It is only later that the compiler says, well now I know what F is,
does it make sense with the actual code of std::sort.

It would be a different story if sort was defined like this

template <class I, class T>
void sort(I first, I last, bool (*comp)(T, T))
{
...
}

because then obviously only the two argument version of your comp function
could match. However std::sort isn't defined like that probably because it
would mean std::sort could only be used with function pointers and not
functors.

john
 
H

hall

John Harrison wrote:

[snip]
It would be a different story if sort was defined like this

template <class I, class T>
void sort(I first, I last, bool (*comp)(T, T))
{
...
}

This is how i thought that sort was defined and thus my confusion, but
as you explain below, this definition would not be a good idea.
because then obviously only the two argument version of your comp
function could match. However std::sort isn't defined like that
probably because it would mean std::sort could only be used with
function pointers and not functors.

john

Thanks!
hall
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top