I have a std::list
and in my class I have myclass::operator<(myclass &other)
defined.
I use the std::list.sort
assuming you don't have NULL pointers in your list just do
bool ptrsorter( myclass *a, myclass *b ) {
return *a < *b;
}
mylist.sort( ptrsorter );
or if you're lucky enough to be using a more recent compiler (with C++0x-support), you can use a lambda-expression:
mylist.sort( []( myclass *a, myclass *b ) { return *a < *b } );
Several answers propose using a predicate that explicitly takes two pointers; this will work for your current case where you have a container of raw pointers, but it won't work for any other dereferenceable type, like smart pointers or iterators.
Why not go the more general route and match any type?
struct indirect_compare
{
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return *lhs < *rhs;
}
}
While a const reference is unnecessary for a T*
, it is necessary for smart pointer types that are relatively expensive to copy (e.g. std::shared_ptr
) or impossible to copy (e.g. std::unique_ptr
).
Alternatively, you might consider using something like Boost's indirect_iterator, which moves the indirection into the iterator and can make for much cleaner code.
I was trying out the template PComp example and since other classes would be using the PComp I stuck in the the include file for the class the std::list was holding. However when I compiled the task I got this:
In member function ‘EcTVoid FdFtTSBFDFTableLoadAppl::IngestTableProducts(const string&, const EcTInt&)’:
/mms_builds/working/jkerich/MMS_SDF/sw/mms/dms/FdFtTSB/src/FdFtTSBFDFTableLoadAppl.C:782:53 error: no matching function for call to ‘std::list<FoFmVirtualTbl*>::sort(<unresolved overloaded function type>)’
myIngestedTables.sort(sorter.PComp<FoFmVirtualTbl>); // sorted list
^
/mms_builds/working/jkerich/MMS_SDF/sw/mms/dms/FdFtTSB/src/FdFtTSBFDFTableLoadAppl.C:782:53 note: candidates are:
In file included from /usr/include/c++/4.8.2/list:64:0,
from /mms_builds/working/jkerich/MMS_SDF/sw/mms/foscommon/common/FoCf/include/FoCfConfigSetup.h:11,
from /mms_builds/working/jkerich/MMS_SDF/sw/mms/foscommon/common/FoCf/include/FoCfTypes.h:156,
from /mms_builds/working/jkerich/MMS_SDF/sw/mms/dms/FdFtTSB/src/FdFtTSBFDFTableLoadAppl.C:18:
/usr/include/c++/4.8.2/bits/list.tcc:353:5: note: void std::list<_Tp, _Alloc>::sort() [with _Tp = FoFmVirtualTbl*; _Alloc = std::allocator<FoFmVirtualTbl*>]
list<_Tp, _Alloc>::
^
/usr/include/c++/4.8.2/bits/list.tcc:353:5: note: candidate expects 0 arguments, 1 provided
/usr/include/c++/4.8.2/bits/list.tcc:430:7: note: void std::list<_Tp, _Alloc>::sort(_StrictWeakOrdering) [with _StrictWeakOrdering = bool (FoFmVirtualTbl::*)(const FoFmVirtualTbl* const&, const FoFmVirtualTbl* const&); _Tp = FoFmVirtualTbl*; _Alloc = std::allocator<FoFmVirtualTbl*>]
list<_Tp, _Alloc>::
^
/usr/include/c++/4.8.2/bits/list.tcc:430:7: note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘bool (FoFmVirtualTbl::*)(const FoFmVirtualTbl* const&, const FoFmVirtualTbl* const&)’
In file included from /ecs/MMS_SDF/RogueWave/13.2/dbg/rw/config/rwconfig_tls.h:9:0,
from /ecs/MMS_SDF/RogueWave/13.2/dbg/rw/compiler.h:5,
from /ecs/MMS_SDF/RogueWave/13.2/dbg/rw/defs.h:46,
from /ecs/MMS_SDF/RogueWave/13.2/dbg/rw/cstring.h:33,
from /mms_builds/working/jkerich/MMS_SDF/sw/mms/foscommon/common/FoCf/include/FoCfTypes.h:11,
from /mms_builds/working/jkerich/MMS_SDF/sw/mms/dms/FdFtTSB/src/FdFtTSBFDFTableLoadAppl.C:18:
The template is this:
template <typename T> bool PComp(const T * const & a, const T * const & b)
{
EcTInt status = a->compareTo(b);
return ((status == -1) ? true : false);
}
the calls I tried in FdFtTSBFDFTableLoadAppl.C were:
myIngestedTables.sort(PComp<FoFmVirtualTbl>); // sorted list
or
FoFmVirtualTbl sorter;
myIngestedTables.sort(sorter.PComp<FoFmVirtualTbl>); // sorted lis
t
Only when the template was declared in FdFtTSBFDFTableLoadAppl did it compile ok. So how would I get this to compile if the template is in some others class include?
You are sorting the pointer values, not the myclass values. You have to write your own predicate to compare pointers by dereference:
template <typename T> bool PComp(const T * const & a, const T * const & b)
{
return *a < *b;
}
std::vector<Foo*> myvec;
std::list<Foo*> mylist;
std::sort(myvec.begin(), myvec.end(), PComp<Foo>);
mylist.sort(PComp<Foo>);
By the way, I think you cannot sort std::list
with std::sort
from <algorithm>
because it is not random access. Use the member function sort
instead as MerickOWA says. (But that's generally less efficient than sorting a random-access container.) Alternatively, you can immediately store your objects in a sorted container like std::set<Foo*, PPred>
, where PPred
is the functor version of the predicate:
struct PPred {
template <typename T> inline bool operator()(const T * a, const T * b) const
{ return *a < *b; }
};
It'll sort the pointer as std::sort( Container ) use the operator< defined T. Here T is myclass*, then it is sorted using comparison over pointer.
You can pass a custom comparator functor to std::sort so make one take takes two myclass* and return the proper comparison :
template<class T>
struct ptr_comparison
{
bool operator()(T* a, T* b) { return *a < *b; }
};
list<myclass*> mylist;
// later
mylist.sort(ptr_comparison<myclass>());