Archived

This topic is now archived and is closed to further replies.

xiuhcoatl

STL is hannering me flat - in need of assistance

Recommended Posts

xiuhcoatl    282
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]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
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

Share this post


Link to post
Share on other sites
xiuhcoatl    282
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

Share this post


Link to post
Share on other sites
xiuhcoatl    282
_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

Share this post


Link to post
Share on other sites
cgoat    132
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).

Share this post


Link to post
Share on other sites
Stoffel    250
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..

Share this post


Link to post
Share on other sites
xiuhcoatl    282
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 order

struct 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 list

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

Share this post


Link to post
Share on other sites
Stoffel    250
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]

Share this post


Link to post
Share on other sites