Overload operator == for STL container - c++

I'm trying to remove a class object from list<boost::any> l
l.remove(class_type);
I tried writing something like this as a member function
bool operator == (const class_type &a) const //not sure about the arguments
{
//return bool value
}
How would you write an overload function to remove an object of class from a std::list of boost::any?

While your signature for operator== looks fine, overloading it for class_type isn't enough as boost::any doesn't magically use it. For removing elements however you can pass a predicate to remove_if, e.g.:
template<class T>
bool test_any(const boost::any& a, const T& to_test) {
const T* t = boost::any_cast<T>(&a);
return t && (*t == to_test);
}
std::list<boost::any> l = ...;
class_type to_test = ...;
l.remove_if(boost::bind(&test_any<class_type>, _1, to_test));

Related

using a map with a comparator as a std::map parameter

Say I define a map with a custom comparator such as
struct Obj
{
int id;
std::string data;
std::vector<std::string> moreData;
};
struct Comparator
{
using is_transparent = std::true_type;
bool operator()(Obj const& obj1, Obj const& obj2) { return obj1.id < obj2.id; };
}
std::map<Obj,int,Comparator> compMap;
is there a good way to ensure that downstream users don't have to implement the comparator to use the map as a map?
for instance my compiler throws an error if I try to pass it to a function with a similar type.
template<class T>
inline void add(std::map<T, int>& theMap, T const & keyObj)
{
auto IT = theMap.find(keyObj);
if (IT != theMap.end())
IT->second++;
else
theMap[keyObj] = 1;
}
add(compMap,newObj); //type error here
EDIT:
I kinda over santitized this to make a generic case. and then overlooked the obvious
template<class T, class Comp, class Alloc>
inline void add(std::map<T, int, Comp, Alloc>& theMap, T const & keyObj)
still having issues with one use not being able to deduce T, but went from 80 erros to 1 so... progress
thanks everyone.
You can typedef the specialised type and use that type inplace of
std::map<...
typedef std::map<Obj,int,Comparator> compMap_t;
inline void add(compMap_t& theMap, Obj const & keyObj)
...
Downstream users either use the type declared by you
using my_important_map = std::map<Obj,int,Comparator>;
or better use functions which take a generic map type,
auto some_function(auto const& map_)
{
//do something with the map and don't care about the ordering
return map_.find(Obj(1));
}

Modify std::less on a shared_ptr

This is what I have:
struct Foo {
int index;
}
std::set<std::shared_ptr<Foo>> bar;
I want to order bar's elements by their indices instead of by the default std::less<std::shared_ptr<T>> function, which relates the pointers.
I read I can type std::set<std::shared_ptr<Foo>, std::owner_less<std::shared_ptr<Foo>>> bar, but I'd prefer to stick to the previous syntax.
I tried defining std::less<std::shared_ptr<Foo>>, but it's not actually being used by the set functions. Is there a way I can achieve this?
If you want to compare by their indices, you'll have to write a comparator that checks by their indices. std::less<> will do the wrong thing (since it won't know about index) and std::owner_less<> will do the wrong thing (since it still won't compare the Foos, but rather has to do with ownership semantics of them).
You have to write:
struct SharedFooComparator {
bool operator()(const std::shared_ptr<Foo>& lhs,
const std::shared_ptr<Foo>& rhs) const
{
return lhs->index < rhs->index;
}
};
and use it:
std::set<std::shared_ptr<Foo>, SharedFooComparator> bar;
You could additionally generalize this to a generic comparator for shared_ptr's:
struct SharedComparator {
template <typename T>
bool operator()(const std::shared_ptr<T>& lhs,
const std::shared_ptr<T>& rhs) const
{
return (*lhs) < (*rhs);
}
};
and then simply make Foo comparable.
You can provide your own specialization of less<shared_ptr<Foo>> in the std namespace.
namespace std
{
template<>
class less<shared_ptr<Foo>>
{
public:
bool operator()(const shared_ptr<Event>& a, const shared_ptr<Event>& b)
{
// Compare *a and *b in some way
}
};
}
Then you can form a set<shared_ptr<Foo>> without a comparator. I needed this for a priority_queue<shared_ptr<Foo>>, where I didn't want to use a priority_queue<Foo*, vector<Foo*>, int (*)(const Foo*, const Foo*)>. I am not proud of it, but it works.

==operator overload only on certain occasions

I am making a project that takes in types as templates. The operator== is already overloaded for chars, ints, strings, etc as you know, but if the user decides to pass in a cstring (null terminated character array) I will need to overload the == for that. Can I choose to only overload the operator== when the user uses cstrings, and use the default == when they dont? How would this be accomplished?
You cannot overload the == operator on a C-string. I am not completely sure why that should be necessary - the C++ string class has defined an implicit conversion from a C-string, and already defines the == operator.
You can't overload operator== for C strings, because they are pointers and operators can be overloaded if at least one operand is a class or enum. What you can do is create your own comparator function and use it in your code instead of ==:
template<typename T>
bool my_equal(const T& a, const T& b) {
return a == b;
}
bool my_equal(const char* a, const char* b) {
return /* your comparison implementation */;
}
Update: you may have to add more overloads to support std::string vs const char* comparisons, as pointed out by TonyD in comments.
You can use type traits to dispatch to the correct function. For example:
#include <type_traits>
template<typename T>
using is_cstring =
std::integral_constant<bool,
std::is_same<T, char const*>::value
|| std::is_same<T, char*>::value>;
template<typename T>
class Thingy
{
public:
bool operator==(Thingy const& rhs) const
{
return equal_helper(rhs, is_cstring<T>());
}
private:
bool equal_helper(Thingy const& rhs, std::true_type) const
{
return strcmp(m_value, rhs.m_value) == 0;
}
bool equal_helper(Thingy const& rhs, std::false_type) const
{
return m_value == rhs.m_value;
}
T m_value;
};

C++ How to Sort Vector making use of Template

C++ How to Sort Vector making use of Template
Hi Guys, thanks for looking at my question.
I got a Templates.h file that goes this way..
/* Template Less Than */
template<typename T>
bool lessThan(T a,T b)
{
return a<b;
}
/* Template greater Than */
template<typename T>
bool greaterThan(T a,T b)
{
return a>b;
}
/* Template Equals */
template<typename T>
bool equals(T a,T b)
{
return a==b;
}
Then i got this class
Map2D
About Map2D..
class Map2D
{
protected:
int x;
int y;
public:
Map2D();
Map2D(int,int);
int getX();
int getY();
};
At my main.cpp i got a vector class of Map2D
vector<Map2D> map2d;
So now i need to sort it by X Ascending.. how do i make use of the template file to do a sort on the vector of it X Ascending.. Consider i will need overload another for DESCENDING later..
Normally i will use
sort(map2d.begin(),map2d.end(),sortByX);
and sortByX will be a struct with overload by it () operator.
But the question now is since i got a template that is lesser than and greater than.. how can i make use of it to sort X by ascending and then another X by descending with the template generic function of Templates.H .
Updates:
I think i need to overload the class Map2D operator > , < and ==
but my question is how do i overload it with the help of MyTemplates.h function such as lesserThan , greaterThan, equals
Thanks.
Define a comparator for your class or simpler, a operator<() overload (which you need to do anyway for your templates to work).
First, fix your templates:
template<typename T>
bool lessThan(const T& a, const T& b)
{
return a<b;
}
template<typename T>
bool greaterThan(const T& a, const T& b)
{
return b<a;
}
template<typename T>
bool equals(const T& a, const T& b)
{
return !(a<b || b<a);
}
Next, define an operator<() on your class.
class Map2D
{
protected:
int x;
int y;
public:
Map2D();
Map2D(int,int);
int getX();
int getY();
// this sample sorts on X dominantly, and Y if X is the same
bool operator <(const Map2D& obj) const
{
return (x < obj.x || (x == obj.x && y < obj.y));
};
}
Now just invoke sort:
std::sort(map2d.begin(), map2d.end());
Invoke using your lessThan template as such:
std::sort(map2d.begin(), map2d.end(), lessThan<Map2D>);
Or your greaterThan template:
std::sort(map2d.begin(), map2d.end(), greaterThan<Map2D>);
In C++11 you could write a lambda function to do it.
Using boost, if you want a "one-step on the fly" functor it would have to be something like:
bind( less<int>, bind(&Map2D::getX(),_1), bind(&Map2D::getX(),_2) )
// or your lessThan<int> which already exists in C++ as less<int>
Not sure if that will work exactly. (Will the 2nd and 3rd binds convert properly to placeholders?) Easier to write a very generic functor that combines what you are trying to do, i.e. extract something from your class (a transformation) then pass that into the predicate.
template< typename Trans, typename Pred >
struct Comparator
{
Comparator( Trans t , Pred p ) : trans( t ), pred ( p )
{
}
template< typename T >
bool operator()( T const& t1, T const& t2 ) const
{
return pred( trans(t1), trans(t2) );
}
private:
Trans trans;
Pred pred;
};
template< typename Trans, typename Pred >
Comparator< Trans, Pred > makeComparator( Trans t, Pred p )
{
return Comparator( t, p );
}
// then in your code
std::sort( map2d.begin(), map2d.end(),
makeComparator( boost::bind( &Map2D::getX(), _1 ), lessThan<int> ) );
should work and you've kept Comparator generic.
(Not sure if boost already offers something like this).
There are a few issues with your code:
Class is missing semicolon at the end.
Your comparison templates should return bool instead of a T.
You miss comparison operators inside your class:
bool operator<(const Map2D &m) const {return /* some code here */ }
bool operator>(const Map2D &m) const {return /* some code here */ }
bool operator==(const Map2D &m) const {return /* some code here */ }
or fix your templates to only use operator<() for all the comparisons (which is a common practice BTW).
When you fix above you just use your templates like that:
sort(map2d.begin(),map2d.end(), lessThan<Map2D>);
sort(map2d.begin(),map2d.end(), greaterThan<Map2D>);
BTW, you do not need custom templates to sort your class in such an easy way. Reuse what is already in STL:
sort(map2d.begin(),map2d.end()); // less
sort(map2d.begin(),map2d.end(), std::greater<Map2D>());
You can find those in functional header. You also cannot use operator==() for sorting but it may be useful for unordered containers introduced in C++11.
EDIT: If your sorting algorithms for Map2D class are fixed (what is lessThan does not change with time) than I suggest following my answer. Otherwise if now you want to sort by X and after a few lines by Y than #MikeSeymour answer may be better suited to your needs.
If you are in C++11, you can write something like this:
std::sort(map2d.begin(), map2d.end(), [](const Map2D& a, const Map2D& b) {
return lessThan(a.getX(), b.getX()); } ); // accending
std::sort(map2d.begin(), map2d.end(), [](const Map2D& a, const Map2D& b) {
return greaterThan(a.getX(), b.getX()); }); // decending
Otherwise you have to implement compare functor, i.e
struct compare
{
bool operator () (const Map2D& a, const Map2D& b)
{
return lessThan(a.getX(), b.getX());
}
};
and then
std::sort(map2d.begin(), map2d.end(), compare());
But really it isn't a good style to have lessThan, greaterThan, since you can compare x directly. And if you want some special comparison for Map2D maybe it is better to make these compare functions only for Map2D objects.
Upd: you can also use just function pointer as your comparator, i.e:
bool compare(const Map2D& a, const Map2D& b)
{
return lessThan(a.getX(), b.getX());
}
and then
std::sort(m.begin(), m.end(), compare);
But you may loss some performance (see comments below).
You first need to overload operators <, > and == to use Map2D with your templates:
class Map2D
{
protected:
int x;
int y;
public:
Map2D();
Map2D(int,int);
int getX();
int getY();
bool operator<(const Map2D& other)const //less then
{
return x < other.x;
}
//other operators is same manner
}
After you have done you just use it:
sort(map2d.begin(),map2d.end(),lessThan<Map2D>);
You can't really. You'll need to define functors (either functions, or classes that overload operator() appropriately) to do the particular object-member comparisons you need, and your function templates don't do that. You need something like:
struct compare_x_less {
// NOTE: you'll need to declare `get_X() const` for this to work.
// You should do that anyway.
bool operator()(Map2D const & a, Map2D const & b) {
return a.get_X() < b.get_X();
}
};
// and similarly for `compare_x_greater` and any other comparisons you need
std::sort(map2d.begin(),map2d.end(),compare_x_less());
In C++11, lambdas can save you a bit of typing:
std::sort(map2d.begin(),map2d.end(),[](Map2D const & a, Map2D const & b) {
return a.get_X() < b.get_X();
});
sort(map2d.begin(),map2d.end(),lessThan<map2d>);
Be aware that lessThan is a prediacte function that should return instead of T value of type bool
Some additional explanation:
// usage
/* Some moments to mention: if you omit third argument, default argument less<T> will be used,
which is enough for built-in types, also you can use predicates already defined in STL:
greater<T>, less<T> or you can provide your own predicate */
sort(map2d.begin(),map2d.end(),lessThan<map2d>);
// header file, where we define predicats which we shall provide as argument to algorithm sort
// predicate expected by function sort has to obey the following rules:
// 1. return bool 2. accept 2 parameters
/*2 variants of predicat*/
// 1) operator< is overloaded for class T, so we can use it to compare instances of that class
template<typename T>
bool lessThan(T a,T b)
{
return a < b;
}
/* 2) operator< not overloaded, when we have to get values of class members by which we are going to compare them
this could be done in various ways, for ex. by means of getters();*/
template<typename T>
bool lessThan(T a,T b)
{
return a.getValueOfMember() < b.getValueOfMember();
}
A good way, I don't think it's the best.
You can overload the operator (<) & (!=) in the class. If you only want to sort for X.
And just use sort(map2d.begin(), map2d.end()) for ascending. and sort(map2d.rbegin(), map2d.rend()) for descending .. And that solves your problem.
OR:
You can make 2 functions to compare 1 relevant to x & the other relevant to Y.
As:
int cmpx(const void* A, const void *B){
Map2D a = *(Map2D *)A;
Map2D b = *(Map2D *)B;
if(a.x < b.x) return -1;
if(a.x == b.x) return 0;
return 1;
}
// And use
qsort(map2d.begin(), (int)map2d.size(), sizeof(Map2D), cmpx);
And so for Y.
Not sure if map2d.rbegin() will sort this descedingly or you'll have to do it on your own as well.

How to write a comparison operator in c++?

I'm having an array of structure containing three fields:
struct data{
int s;
int f;
int w;
};
struct data a[n];
In order to sort the array of structure based on field f I'm using my own comparison operator :
bool myf( struct data d1,const struct data d2){
return d1.f < d2.f ;
}
The above operator works fine in inbuilt sort() function :
sort(a,a+n,myf);
but it's not working for upper_bound() function :
upper_bound(a,a+n,someValue,myf);
Can anyone tell me where am I doing wrong ? Is my comparison operator wrong ? If it's wrong, why is it working for sort() function and not upper_bound() ?
I'm getting following on compilation :
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘_FIter std::upper_bound(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = data*, _Tp = int, _Compare = bool (*)(data, data)]’:
prog.cpp:37: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:2243: error: conversion from ‘const int’ to non-scalar type ‘data’ requested
All you actually need here is to create operator< for your type:
inline bool operator<( const data& lhs, const data& rhs ) {
return lhs.f < rhs.f;
}
and standard algorithms will magically work for you.
In C++ you don't need struct when referring to a type like in C, and you want to pass by const reference to avoid copying.
Edit 0:
The above overloads standard comparison operator < for your type. You would use it implicitly as:
data values[N];
// ... populate
std::sort( values, values + N );
or explicitly with a standard functor:
std::sort( values, values + N, std::less<data>());
Edit 1:
See that compiler tells you _Tp = int in the warning? You need to pass an instance of data as third argument to upper_bound, not int:
data xxx = { 0, 1, 7 };
auto iter = std::upper_bound( values, values + N, xxx );
You can also create overloads for comparing to integers, like:
inline bool operator<( const data& lhs, int rhs ) {
return lhs.f < rhs;
}
inline bool operator<( int lhs, const data& rhs ) {
return lhs < rhs.f;
}
for your original invocation to work.
Primarily, it isn't working because the upper_bound overload that accepts a custom sorting takes four parameters:
// http://en.cppreference.com/w/cpp/algorithm/upper_bound
template< class ForwardIt, class T, class Compare >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value,
Compare comp );
It was suggested in another answer that you introduce operator< for your type. However, do not do this just for the sake of one specific sorting. Only introduce comparison operators iff they actually make sense for your type.
If you don't follow this rule, future programmers might use your type and wonder about why something works that shouldn't, or vice versa. Your future evil twin may also want to use another sorting for his purpose.
E.g., it makes sense for a complex-datatype class, a SIMD-class (like std::valarray), but it doesn't make any specific sense for example for an Employee class:
Employee foo, bar;
if (bar > foo) {
// is bar taller than foo?
// is bar older than foo?
// is bar working better than foo?
// is bar bigger newbie than foo?
}
Instead, you could do it like this:
namespace employee_ordering {
struct by_name_ascending {
bool operator() (Employee const &lhs, Employee const &rhs) const {
return lhs.name() < rhs.name();
}
};
struct by_name_descending {
bool operator() (Employee const &lhs, Employee const &rhs) const {
return lhs.name() > rhs.name();
}
}
};
....
upper_bound(first, last, ..., employee_ordering::by_name_ascending());