Generic way to create comparer for objects behind pointers - c++

I use data structures, and I sort these data structures a lot. These data structures are holding pointers to objects, not directly the objects themselves. Now I can write a simple comparison functor, or function, to tell the sort algorithm how to sort the pointers:
struct Object_ptr_comparer {
bool operator()(const Object* first, const Object* second) {
return *first < *second;
}
};
And use for example std::sort:
Object_ptr_comparer comp;
std::sort(data_str.begin(), data_str.end(), comp);
The only problem with this solution that I have to write extra pointer comparator functor for any type of class. Yes, I could use inheritance and polymorphism to write only the comparator of some root class, but I don't want to. Is there any other smart way to do this?

What about a template?
struct ptr_comparer {
template<typename T>
bool operator()(const T* first, const T* second) {
return *first < *second;
}
};
used like this:
std::sort(data_str.begin(), data_str.end(), ptr_comparer());

That's what templates are for!
struct ptr_comparer {
template<class Object>
bool operator()(const Object* first, const Object* second) const {
return std::less<Object>()(*first, *second);
}
};
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
Since I've templated the operator rather than specializing the comparer directly, the compiler can deduce the types, so we don't have to put the types directly.
I use std::less rather than operator<, because it safely compares pointers to pointers (like char**), rather than relying on Undefined Behavior. std::less falls back on operator<, so it doesn't add any complexity to calling code, and there should be no downside.
I'm certain this one compiles

Related

Generic operator== for non-pod objects

While doing some unit tests I want to be able to compare some pretty simple structs (they contain only public data members). I could write a operator== for all of them separately but it would be cumbersome and repetitive. So I decided to try to do this in a generic way. Yet there is a problem - some of them are not POD as some of their fields have non-POD type, let's say a std::list for an example.
struct NonPod {
std::list<int> lst;
};
struct NonPod2 {
std::list<NonPod> lst;
};
template<class T>
bool operator==(const T& lhs, const T& rhs) {
//what should I put here to make it work safely
//to compare NonPod with other NonPod
//ant NonPod2 with other NonPod2
}
AFAIK, to compare POD safely I could just use std::memcmp and it would be all fine. Is it possible to do generic operator== for non-POD types as well? If so, how?
Sadly, there is no way to do this in C++17 (or earlier). C++20 will allow you to add:
auto operator<=>(const class_name&) const = default;
to each class. This will give you all the comparison operators defined in the obvious way.
If the classes are being created by a code generator, then adding a comparison function should be easy.

Sort vector of objects for binary search

I have the following class:
struct EdgeExtended {
int neighborNodeId;
int weight;
int arrayPointer;
bool isCrossEdge;
};
I want to have a vector of such objects, sort it by neighborNodeId. Then I want to search for a particular neighborNodeId and return a reference to the found object inside the vector by binary search. Previously I used a map for that, so it was something like that:
map<int, EdgeExtended> neighbours;
.....
auto it = neighbours.find(dnodeId);
if (it != neighbours.end()) {
edgeMap = it->second;
}
Instead of
map<int, EdgeExtended> neighbours;
I want to have
vector<EdgeExtended> neighbours;
and retain as much as the old code the same.
I want to benchmark if the vector is faster than the map, since I am building thousands of vectors(or maps) and each vector (map) is relatively small (~10 items). I do not know how to a) make objects sortable by neighborNodeId and b) how to use binary search that searches for a particular member of the class (neighborNodeId). Sorry for the noob question. I am counting on your help.
You need a custom comparator function that takes two EdgeExtended objects and compares the fields you're interested in and that you can pass to both sort and binary_search as a third or fourth argument, respectively.
It can be conveniently done with a lambda function:
auto Comp = [](const EdgeExtended& e1, const EdgeExtended& e2)
{
return e1.neighborNodeId < e2.neighborNodeId;
};
If you stuck pre-C++11, write a class with overloaded operator() instead:
struct Comp {
bool operator()(const EdgeExtended& e1, const EdgeExtended& e2) const
{
return e1.neighborNodeId < e2.neighborNodeId;
}
};
Extending on jrok's answer, if you encounter similar problems more often, a reusable templated comparator which uses any member of a class comes in very handy.
template<class T, class U>
class CompareByMember {
U (T::*mem); // ugly syntax for member pointer of type U in class T
public:
CompareByMember(U (T::*mem)) : mem(mem) {}
bool operator()(const T &a, const T &b) {
return (a.*mem) < (b.*mem); // ugly syntax for member pointer access
}
};
As you can see, the syntax for pointers to class members is pretty strange, but once wrapped in this functor you don't have to care about it. One remaining "issue" is that you'd have to write the template parameters <T, U> each time you want to use this functor. But using type deduction this problem is solved, introducing a little helper function (note that its name is lower case):
template<class T, class U>
CompareByMember<T,U> compareByMember(U (T::*mem)) {
return CompareByMember<T,U>(mem);
}
This results in client code like this:
std::vector<EdgeExtended> v = ...;
std::sort(v.begin(), v.end(), compareByMember(&EdgeExtended::neighborNodeId));
Simple demonstration
For member functions, a similar templated functor can be written, using the only slightly different member function pointer syntax. You can also overload the call operator in the functor to accept raw pointers of T as well as any smart pointer wrapping around T* (using templates again).

C++: use own class in a multiset container

at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.
I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.
Here is my general idea of my class definition:
class object {
public:
int first;
string second;
object(int f, string s) {
first = f;
second = s;
}
bool operator<(const object &comp) {
return first < comp.first;
}
};
This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.
Here is a short code extract from my main function:
includes ...
//code omitted
int main() {
multiset<object*> mmset;
mmset.insert(new object(10, "test"));
mmset.insert(new object(11, "test"));
return 0;
}
After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.
code extract from the stl:
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.
I would really appreciate it if someone could help me.
Best Greetings
Tom
You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.
It seems like you really just want a multiset<object>:
multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");
Now it will use < to compare the objects themselves.
If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:
auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);
Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.
Thank you for your help. That's seems to be a good solution to solve this problem.
I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :)
I will post it just as information for other seekers with the same problem.
You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content.
The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.
class object {
int first;
string second;
object() { };
object(int f, string s) {
first = f;
second = s;
}
bool operator()(const object *comp1, const object *comp2) const {
return comp1->first < comp2->first;
}
}
The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:
multiset(object*, object) mmset;
You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.

How would I encapsulate a mergesort program for general customer use in C++?

I currently have a mergesort that accepts a list of ints and makes an array out of them, then sorts them, and prints out the sorted array. Currently all of the code is in a single .cpp file.
What is a good way to provide the code to someone who wants to sort an array of user defined objects?
My instincts are to provide a virtual method only file (interface) and require my user to override comparison operators and read/write methods.
Would it be best to move away from arrays and use a linked list?
If this is too vague/subjective then just slap me around and close it. I just wanted some ideas beyond my own.
Use templates to implement the sort and use a pointer array instead of an array of objects ask for a functor that implements the comparison and also provide a default functor which uses < operator to do the comparison.
This is how to do it using the standard libraries.
If the customer has their own type they need to define operator< for sorting and operator<< for printing to an ostream:
class Type {
//...
};
bool operator<(const Type& lhs, const Type& rhs) {
//...
}
ostream& operator<<(ostream& os, const Type& object) {
//...
}
vector<Type> originals;
vector<Type> values = originals;
stable_sort(values.begin(), values.end());
copy(values.begin(), values.end(),
ostream_iterator<Type>(cout, "\n"));
Your customer would have to have a very good reason not to do it this way.
No, you don't need linked-list.
The simplest solution without digging too much for functors:
template <class T, int size>
class MergeSort
{
T* arr[size];
MergeSort(T* array[size])
{
// ...
}
void Sort()
{
// The rest is simple...
}
};

How deep should be the copy (assignment) of a type-erased map

I am writing a library in C++ for which I implemented a map wrapper with type erasure. The wrapper is structured as in this wonderful article: http://www.cplusplus.com/forum/articles/18756/.
TLDR:
template<typename K, typename V>
class AnyMap
{
class MapConcept
{
public:
// Lots of pure virtual methods...
// These mimic the intersection of STL and Boost maps' interfaces
// Example:
virtual size_type size() = 0;
};
template<typename ActualMapType>
class MapModel : MapConcept
{
ActualMapType m;
public:
// Implementations of the parent's virtual methods...
// These basically just call the same method on member m.
// Example:
size_type size() { return m.size(); }
};
MapConcept* mapConcept;
public:
// Again, the STL and Boost maps' interface methods
// Example:
size_type size() { return mapConcept->size(); }
};
I'm not sure whether I will expose this map as part of the finished library or tuck it away as a helper class, but either way I'm wondering what do with the assignment operator.
Currently, I have something like this:
AnyMap& AnyMap::operator=(const AnyMap& other) {
delete mapConcept;
mapConcept = other.mapConcept->clone();
return *this;
}
This means that if I create two maps with say an STL's map and a Boost's unordered_map and then assign one to the other, both will now have the same map type underlying them.
std::map<string, int> stlMap;
boost::unordered_map<string, int> boostMap;
// insert some stuff into maps
AnyMap<string, int> stlAnyMap( stlMap );
AnyMap<string, int> boostAnyMap( boostMap );
stlAnyMap = boostAnyMap;
// now stlAnyMap has a copy of boostMap
So, this makes some sense because the contents of the map assigned to are what's expected. However, I suspect that usually the map types will differ by one of the type arguments with default values (such as Hash in Boost::unordered_map). So, maybe it should retain the underlying map type. I think, this can be done with something like the following:
AnyMap& AnyMap::operator=(const AnyMap& other) {
mapConcept->clear();
mapConcept->insert( other.mapConcept->begin(), other.mapConcept->end() );
return *this;
}
This should work because of the templated insert method:
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
By the way, if anyone is wondering how I dealt with the iterators: I used Thomas Becker's any_iterator - http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html.
So, what do you guys think? I'm leaning toward the latter approach, but I'd like to hear any arguments for either side.
Thanks in advance!
EDIT: Here is the first argument against (perhaps, you could tell me how important this is): the contents of one map type might now map one-to-one to another map if one predicate distinguishes two keys in the map while the other considers them the same.
Do you want the map wrapper to have value semantics or not? That will determine how deep the copy has to be. In any case, the implementation of other.mapConcept->clone() will be polymorphic (this is, after all, the essence of the C++ type erasure technique) and result in a dispatch to a call in the MapModel subclass that looks like this
virtual MapModel *clone() { return new MapModel(m); } // covariant return type
So everything boils down to what ActualMapType's copy constructor does (since the member variable m will be a copy.)
Since the technique was invented to get value semantics, I think retaining that feature is consistent with the principle of Least Surprise. Moreover, the point is to have a fixed interface. The implementation (STL or boost or whatever) is irrelevant by design, so there is little point in trying to retain the implementation in any particular object instance.
Incidentally your implementation of operator= for the "standard" case is not exception safe. The copy-and-swap idiom (perhaps with a custom swap() method) works better
AnyMap( AnyMap const& other )
: mapConcept( other.mapConcept ? other.mapConcept->clone() : 0)
{}
AnyMap& operator= ( AnyMap rhs ) // note temporary: invokes copy constructor
{ std::swap( mapConcept, rhs.mapConcept ) ; return *this; }