STL is hannering me flat - in need of assistance

Started by
6 comments, last by xiuhcoatl 21 years, 11 months ago
I have a vector, I want to sort it. When I try to compile I get this error (abbr): error C2664: '()' : cannot convert parameter 1 from 'class ModeInfo *' to 'class ModeInfo &' see reference to function template instantiation 'void __cdecl std::_Unguarded_insert(class ModeInfo ** ,class ModeInfo *,struct modeSort)' being compiled The call is made as such; m_modeList is declared; MODE_VECTOR is defined as:
          
typedef std::vector<ModeInfo *>	 MODE_VECTOR
MODE_VECTOR	m_modeList;
std::sort( m_modeList.begin(), m_modeList.end(), modeSort() );

    
if the ModeInfo class is needed let me know and i'll post it - I didn't want to waste a lot of space displaying the declaration. Current troubleshooting: What bothers me is that the first term is the issue - the SGI guide for stl states that vector.begin() and vector.end() both return a const_iterator ( just pointing to different elements ). MSDN documentation reflects the same information - in fact sample code is shown using std::sort( eg.begin(), eg.end() ). That example sort just uses a "less than" instead of the binary_function but the terms in question are prototyped the same so this error makes no sense. Algorthm.h is as follows (formatted):
        
template<class _RI, class _Ty, class _Pr> inline
void _Sort_0(_RI _F, _RI _L, _Pr _P, _Ty *)
{
    if (_L - _F <= _SORT_MAX)
	_Insertion_sort(_F, _L, _P);
    else
    {_Sort(_F, _L, _P, (_Ty *)0);
     _Insertion_sort(_F, _F + _SORT_MAX, _P);
     for (_F += _SORT_MAX; _F != _L; ++_F)
	_Unguarded_insert(_F, _Ty(*_F), _P);
    }
}
        
if I was a betting man then I'd say that either the documentation was hosed, the SGI implementation is slightly different, or the _Unguarded_insert call is wrong. I am getting to like STL but am by no means an expert - thank you in advance for a solution or just a direction to help me figure this out. Sorry this post is a little lenghty.. #dth-0 [edited by - xiuhcoatl on May 1, 2002 1:14:15 AM] [edited by - xiuhcoatl on May 1, 2002 1:20:03 AM] [edited by - xiuhcoatl on May 1, 2002 1:21:00 AM] [edited by - xiuhcoatl on May 1, 2002 1:21:51 AM] [edited by - xiuhcoatl on May 1, 2002 1:24:38 AM]
"C and C++ programmers seem to think that the shortest distance between two points is the great circle route on a spherical distortion of Euclidean space."Stephen Dewhurst
Advertisement
Judging from the info that you have given, I''d bet that one of your problems is with your declaration of the vector. Since the vector, like much of the other STL classes, is a template, you always need to give it a template argument like so:

typedef std::vector<int> MODE_VECTOR;

''int'' can, of course, be replaced by any type (even your own types if they overload the proper operators).

-D
Apologies -

The typedef for the MODE_VECTOR is properly done - I didn''t format my post correctly and the chevrons got removed.

Once I find the posting guide I''ll correct the original post.

#dth-0
"C and C++ programmers seem to think that the shortest distance between two points is the great circle route on a spherical distortion of Euclidean space."Stephen Dewhurst
_GRRR_

figured it out -
It''s sort of like waiting for a bus and lighting a cigarette...

Call should be:
std::sort( *(m_modeList.begin()), *(m_modeList.end()), modeSort() ); 


or modeSort should deal with pointers instead of addresses..

My bad..

#dth-0
"C and C++ programmers seem to think that the shortest distance between two points is the great circle route on a spherical distortion of Euclidean space."Stephen Dewhurst
quote:Original post by xiuhcoatl
Call should be:
std::sort( *(m_modeList.begin()), *(m_modeList.end()), modeSort() ); 


or modeSort should deal with pointers instead of addresses..


You''re using this wrong. The correct call should look like:

std::sort( m_modeList.begin(), m_modeList.end(), modeSort);

modeSort is a function, so you want to pass the function address, which is modeSort WITHOUT the parentheses.

modeSort should be a function looking like:

bool modeSort(ModeList*& ptr1, ModeList*& ptr2);

which would do the comparison using the pointers, and returns true if (*ptr1) < (*ptr2).
If modesort is a functor, the declaration is correct. The function needs to take pointers as parameters, though. Here''s an example of how I usually do it:

  #include <vector>#include <algorithm>using namespace std;class Widget{    int m_data; // some arbitrary data    public:        // I like making my class predicates members of the class    struct Predicate;    friend Widget::Predicate;    struct Predicate    {        bool operator () (const Widget *lhs, const Widget *rhs) const        {            return lhs->m_data < rhs->m_data;        }    };};void sortWidgetVector (vector<Widget*> &vec){    sort (vec.begin (), vec.end (), Widget::Predicate ());}  


Also, you can overload operator < for your class if there is only one way you''re going to sort things, and then use a templated predicate that sorts pointed-to types. Scott Meyers has an example of this in his Effective STL book, but I don''t have it handy right now--it''s pretty easy to bang out yourself, though, or if someone wants to post it..
modeSort was/is a functor and needed to be passed that way, it''s declaration was the key and my oversight. I was trying to get a little cute and adhere to [item 22] but eventually just changed the modeSort functor to accept pointers. The use of a functor outweighed overloading the lessthan operator because it would be logically ambiguous in certain contexts. Final declaration looks like this in case anyone is interested:


  //	Function used to sort the modes in the desired orderstruct modeSort : public std::binary_function<ModeInfo*, ModeInfo*, bool>{	//	operator()	//	Functor to assist in sorting the ModeInfo objects.	//	XXX - _ASSERT only verifies	pointer non-null	bool operator()(ModeInfo* p1, ModeInfo* p2)	{		_ASSERT(p1);		_ASSERT(p2);				//	By format first. High to Low.		if( p1->format > p2->format )		return false;		if( p1->format < p2->format )		return true;		//	Then width	High to Low		if( p1->Width() < p2->Width() )		return false;		if( p1->Width() > p2->Width() )		return true;		//	Then Height High to Low		if( p1->Height() < p2->Height() )	return false;		if( p1->Height() > p2->Height() )	return true;				//	XXX - This function is supposed to be irreflexible, or 		//	if( f(x,y) && f(y,x) ) == false then they are equal, test and determine		//	what this should be.		return false;	}};call - //	Sort the liststd::sort( m_modeList.begin(), m_modeList.end(), modeSort() );  
"C and C++ programmers seem to think that the shortest distance between two points is the great circle route on a spherical distortion of Euclidean space."Stephen Dewhurst
Ah, the hierarchical compare, beautiful stuff. I applaud your use of binary_function. I do have two suggestions:
1) Make the operator () a const function--it doesn't change any members of the struct, and some pickier compilers won't be able to use the functor if it's non-const. If Width () and Height () aren't constant functions, they should be. Also make the arguments const. It's not correct till it's const-correct.

2) I have a general form for the hierarchical compare that does less operations but has the same logical format as yours. This is very important because this function is called a huge number of times during a sort. Here's an example:

    bool operator () (const ModeInfo *lhs, const ModeInfo *rhs) const{  int compare = lhs->format - rhs->format;  if (compare)    return compare < 0;  compare = lhs->Width () - rhs->Width ();  if (compare)    return compare < 0;  return lhs->Height () < rhs->Height ();}    

This accomplishes the same thing, but with less conditional jumps for some reason. If you look at the generated assembly for the two versions of the functions, there's about a 15% reduction in calls using my method (on MSVC 6.0 at least). Your compiler mileage may vary.

[edited by - Stoffel on May 2, 2002 12:05:21 PM]

This topic is closed to new replies.

Advertisement