Using sets and overloading operators in C++ - c++

So for class this week I have to use a set to read in the Declaration of Independence and the US Constitution from a .txt file, store them in sets, and overload operator* to find and return the intersection of the two sets.
Reading everything in is not a problem, neither is finding out the intersection in the sets. What I'm having a lot of trouble with is overloading operator*. I keep getting two errors:
no operator "*" matches these operands
and
binary "*":'std::set<_Kty>' does not define this operator or a conversion to a type acceptable to the predefined operator
Here is my code so far:
From main:
Reader r;
std::set<std::string> d, c;
d = r.GetDeclaraton();
c = r.GetConstitution();
Set dec(d), con(c);
Set intersection = dec * con;
The errors are coming from that last line of main.
From Set.h
class Set
{
public:
std::set<std::string> s;
Set(void);
Set(std::set<std::string> set)
{
s = set;
}
~Set(void);
std::set<std::string> operator* (const std::set<std::string> &rhs)
{
std::set<std::string> newset;
std::set<std::string>::iterator rhsiter = rhs.begin(), result;
while (rhsiter != rhs.end())
{
result = s.find(*rhsiter++);
if (result != rhs.end())
{
newset.insert(*result);
}
}
return newset;
}
};

You need
Set operator* (const Set &rhs) const
because this is a binary operator with two Sets as arguments. Your attempt would only work if your Set was deriving std::set.
The return type here is Set. It makes more sense to be the same as the input arguments, and this is also consistent with your usage in main. So in this case you need to modify the definition to construct and return a Set instead of an std::set (or rather you need not because an std::set can be implicitly converted to a Set).
Note also I made operator* a const member function, since it's not modifying its object.

operator* is defined in your custom Set so the left-hand-side argument must be a Set, but in dec.s * con.s you're using .s which accesses the member std::set fields, and there's no operator* defined for a left-hand Set and rhs-hand std::set.
You could change to dec * con.s, but it'd be better to change the operator* rhs argument to a const Set& too, and use rhs.s inside the operator... less confusing!

In my opinion its better to write a global or friend operator. Also, for intersection I would use the & operator, for union the | or + operator while, difference: -...
Why global operators? With global operators you can write an operator for your class even if the left operand is not your class. For example in case of a matrix class you can easily write a global operator that multiplies together a float and a matrix while as a matrix member operator you could write only an operator where your matrix is on the left.
Example:
template <typename T>
inline std::set<T> intersection(const std::set<T>& smaller, const std::set<T>& larger)
{
std::set<T> result;
for (auto it=smaller.begin(),eit=smaller.end(); it!=eit; ++it)
{
if (larger.find(*it) != larger.end())
result.insert(*it);
}
return result;
}
template <typename T>
inline std::set<T> operator & (const std::set<T>& a, const std::set<T>& b)
{
if (a.size() < b.size())
return intersection(a, b);
return intersection(b, a);
}
class Set
{
public:
std::set<std::string> s;
Set() {}
Set(std::set<std::string> _s) : s(_s) {}
friend Set operator & (const Set& a, const Set& b)
{
return Set(a.s & b.s);
}
};
int test()
{
std::set<std::string> s, t;
s.insert("aa");
s.insert("bb");
t.insert("bb");
t.insert("cc");
std::set<std::string> u(s & t);
Set ss(s), st(t);
Set result(ss & st);
return 0;
}

Related

Comparsion between structs for a set

This code works but having a struct called ptrcomp outside the weighted_pointer seems (to me) that they are different things. I tried some different ways and even googled it, but I haven't found anything that works like this.
struct node{
unsigned int oper;
void * a;
void * b;
};
struct weighted_pointer{
mutable int weight;
unique_ptr<node> pointer;
};
struct ptrcomp{
bool operator()(const weighted_pointer & lhs, const weighted_pointer & rhs) {
return tie(lhs.pointer->oper, lhs.pointer->a, lhs.pointer->b) < tie(rhs.pointer->oper, rhs.pointer->a, rhs.pointer->b);
}
};
set<weighted_pointer,ptrcomp> gate;
My objective is to make the std::set working. And possibly write it like set<weighted_pointer>.
having a struct called ptrcomp outside the weighted_pointer seems (to me) that they are different things.
That's how things really are. weighted_pointer is data, while ptrcomp is a way to compare the data. So, these two really are different things, and there is nothing wrong with your code.
If it happens that you have one canonical way of comparing your data, make it into operator <:
bool operator < (const weighted_pointer & lhs, const weighted_pointer & rhs) {
return tie(lhs.pointer->oper, lhs.pointer->a, lhs.pointer->b) < tie(rhs.pointer->oper, rhs.pointer->a, rhs.pointer->b);
}
std::set will happily use it, if you use it as std::set<weighted_pointer> (in fact, std::set has the second template parameter defaulted to std::less<T>, which is a comparator class that uses operator <).
If you change your code to
struct weighted_pointer {
mutable int weight;
unique_ptr<node> pointer;
bool operator < (const weighted_pointer & rhs) const;
};
bool weighted_pointer::operator < (const weighted_pointer & rhs) const {
return tie(pointer->oper, pointer->a, pointer->b) < tie(rhs.pointer->oper, rhs.pointer->a, rhs.pointer->b);
}
then it will work and you won't need a comparator ptrcomp for the set and can use the type set<weighted_pointer> as you wished. (You can also move the definition into the struct if you wish.)
struct weighted_pointer {
// ...
struct compare {
// ...
};
};
set<weighted_pointer,weighted_pointer::compare> gate;
// better
using weighted_pointer_set = set<weighted_pointer,weighted_pointer::compare>;
weighted_pointer_set gate;
This is how I see this usually done.
Having a std::set<weighted_pointer> means that the set uses std::less to compare the elements. This in turn calls operator< on the respective type, so if you provide an implementation of that operator it'll work.

== operator overloading with struct

I'm trying to define an == operator within a struct, like this:
struct names {
string fname;
string lname;
bool operator==(names a, names b) {
return (a.fname == b.lname);
}
};
However, the compiler says:
..\src\trash.cpp:10:33: error: 'bool names::operator==(names, names)' must take exactly one argument
Why is this?
If you overload a binary operator as a member function, then it should only take one argument. The first operand is the object the operator is called on (i.e. *this); the second operand is the single function argument.
struct names {
//...
// better to pass by reference;
// make the function 'const' so it can be used on constant objects
bool operator==(names const & rhs) const {
return this->fname == rhs.lname;
}
};
Alternatively, you can overload it as a non-member function, with two arguments:
bool operator==(names const & lhs, names const & rhs) {
return lhs.fname == rhs.lname;
}
If this needed access to private members (which isn't the case in this example), then it would have to be a friend. You can define friends inside the class definition; in which case the code would look exactly the same as your example, only with friend in front of the function declaration.
(Of course, this isn't a sensible definition of equality since it's not symmetric. Many algorithms will break if you can have a == b but not b==a, as you can with this definition. lhs.fname == rhs.fname && lhs.lname == rhs.lname would make more sense.)
operator== is meant to compare two objects for equality. You have it appearing to compare the first and last names for different objects, presumably to catch duets like George Lazenby and Emma George.
I'd make it a member function of the class and use this for one of the objects:
bool operator== (const names &rhs) const {
return (this->fname == rhs.fname) && (this->lname == rhs.lname);
}
Do:
As member function:
struct names {
string fname;
string lname;
bool operator==(const names& rhs) const { /* Your code */ }
};
or as free function:
bool operator==(const names& lhs, const names& rhs) const { /* Your code */ }

How to create a set with my customized comparison in c++

Could someone explain me what is going on in this example here?
They declare the following:
bool fncomp (int lhs, int rhs) {return lhs<rhs;}
And then use as:
bool(*fn_pt)(int,int) = fncomp;
std::set<int,bool(*)(int,int)> sixth (fn_pt)
While the example for the sort method in algorithm library here
can do like this:
bool myfunction (int i,int j) { return (i<j); }
std::sort (myvector.begin()+4, myvector.end(), myfunction);
I also didn't understand the following:
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
I was trying to make a set of C-style string as follows:
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
set <wrap, compare> myset;
I thought I could create a set defining my sorting function in a similar as when I call sort from algorithm library... once it didn't compile I went to the documentation and saw this syntax that got me confused... Do I need to declare a pointer to a function as in the first example i pasted here?
struct classcomp {
bool operator() (const int& lhs, const int& rhs) const
{return lhs<rhs;}
};
Defines a functor by overloading the function call operator. To use a function you can do:
int main() {
std::set <wrap, bool (*)(wrap,wrap)> myset(compare);
return 0;
}
Another alternative is to define the operator as a part of the wrap class:
struct wrap {
char grid[7];
bool operator<(const wrap& rhs) const {
return strcmp(this->grid, rhs.grid) == -1;
}
};
int main() {
wrap a;
std::set <wrap> myset;
myset.insert(a);
return 0;
}
You're almost there... here's a "fixed" version of your code (see it run here at ideone.com):
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
typedef struct
{
char grid[7];
} wrap;
bool compare(wrap w1, wrap w2) // more efficient: ...(const wrap& e1, const wrap# w2)
{
return strcmp(w1.grid, w2.grid) < 0;
}
set <wrap, bool(*)(wrap, wrap)> myset(compare);
int main() {
wrap w1 { "abcdef" };
wrap w2 { "ABCDEF" };
myset.insert(w1);
myset.insert(w2);
std::cout << myset.begin()->grid[0] << '\n';
}
"explain [to] me what is going on in this example"
Well, the crucial line is...
std::set<wrap, bool(*)(wrap, wrap)> myset(compare);
...which uses the second template parameter to specify the type of function that will perform comparisons, then uses the constructor argument to specify the function. The set object will store a pointer to the function, and invoke it when it needs to compare elements.
"the example for the sort method in algorithm library..."
std::sort in algorithm is great for e.g. vectors, which aren't automatically sorted as elements are inserted but can be sorted at any time. std::set though needs to maintain sorted order constantly, as the logic for inserting new elements, finding and erasing existing ones etc. all assumes the existing elements are always sorted. Consequently, you can't apply std::sort() to an existing std::set.
"this keyword operator (not being followed by an operator as in a op. overload)... what is the meaning of it? Any operator applied there will have that behavior? And this const modifier... what is the effect caused by it?
operator()(...) can be invoked on the object using the same notation used to call a function, e.g.:
classcomp my_classcomp;
if (my_classcomp(my_int1, my_int_2))
std::cout << "<\n";
As you can see, my_classcomp is "called" as if it were a function. The const modifier means that the code above works even if my_classcomp is defined as a const classcomp, because the comparison function does not need to modify any member variables of the classcomp object (if there were any data members).
You almost answered your question:
bool compare(wrap w1, wrap w2)
{
return strcmp(w1.grid, w2.grid) == -1;
}
struct wrap_comparer
{
bool operator()(const wrap& _Left, const wrap& _Right) const
{
return strcmp(_Left.grid, _Right.grid) == -1;
}
};
// declares pointer to function
bool(*fn_pt)(wrap,wrap) = compare;
// uses constructor with function pointer argument
std::set<wrap,bool(*)(wrap,wrap)> new_set(fn_pt);
// uses the function directly
std::set<wrap,bool(*)(wrap,wrap)> new_set2(compare);
// uses comparer
std::set<wrap, wrap_comparer> new_set3;
std::sort can use either a function pointer or a function object (http://www.cplusplus.com/reference/algorithm/sort/), as well as std::set constructor.
const modifier after function signature means that function can't modify object state and so can be called on a const object.

How to modify the existing stl find function in C++?

Given that I have a data structure,
struct data{
int val;
};
struct data A[LEN]; // LEN: some length.
// the below operator would be used in sorting.
bool operator < (struct data &a1, struct data &a2){
return a1.val < a2.val;
}
int main(){
// fill up A.
sort(A, A+LEN); // sort up A
/*Now I want something like this to happen ..
x = find(A, A+LEN, value); -> return the index such that A[index].val = value,
find is the stl find function ..
*/
}
How do you do that ?
And for any stl function how do you get to know which operators to override so that it works in the given condition ?
The modifications needed to find elements in such a case are pretty minimal. First, you want to make your operator< take its arguments as const references (technically not necessary for the current exercise, but something you want to do in general):
bool operator < (data const &a1, data const &a2){
return a1.val < a2.val;
}
Then (the part that really matters specifically for std::find) you also need to define an operator==:
bool operator==(data const &a, data const &b) {
return a.val == b.val;
}
Note, however, that you don't have to define this if you use a binary search instead:
auto pos = std::lower_bound(data, data+LEN, some_value);
This will just use the operator< that you'd already defined. If the items are already sorted anyway, this will usually be preferable (generally quite a bit faster unless LEN is quite small).
If you only want to make std::find work for your array of structure, you need to define operator== for struct data:
struct data
{
data(int value=0) : val(value) {}
int val;
};
bool operator==(const data& l, const data& r) { return l.val == r.val;}
auto x = find(A, A+LEN, value);
OR
auto x = find(A, A+LEN, data(value));
To get index of value in A, use std::distance
std::distance(A, x);
Note:
For more sufficent search with sorted container, use std::lower_bound, std::uppper_bound, std::binary_search instead.
auto lower = std::lower_bound(A, A+LEN, data(3));
auto upper = std::upper_bound(A, A+LEN, data(3));
Your operator< function signature better be like:
bool operator < (const data &a1, const data &a2)
// ^^^^^ ^^^^^

Overriding an operator using const for both parameters in C++

I'm trying to create an overridden operator function using both const parameters, but I can't figure out how to do it. Here is a simple example:
class Number
{
Number()
{
value = 1;
};
inline Number operator + (const Number& n)
{
Number result;
result.value = value + n.value;
return result;
}
int value;
}
What I am trying to do here is pass in two arguments into the addition function that are both const and return the result without changing anything in the class:
const Number a = Number();
const Number b = Number();
Number c = a + b;
Is this possible and how would I go about doing this?
Thanks,
Dan
inline is understood in class declarations so you don't need to specify it.
Most idiomatically, you would make operator+ a non-member function declared outside the class definition, like this:
Number operator+( const Number& left, const Number& right );
You might need to make it a friend of the class if it needs access to Number's internals.
If you have to have it as a member function then you need to make the function itself const:
Number operator+( const Number& n ) const
{ // ...
For classes like Number, operator+ is typically implemented in terms of operator+= as usually you want all the usual operators to work as expected and operator+= is typically easier to implement and operator+ tends not to lose any efficiency over implementing it separately.
Inside the class:
Number& operator+=( const Number& n );
Outside the class:
Number operator+( const Number& left, const Number& right )
{
return Number( left ) += right;
}
or even:
Number operator+( Number left, const Number& right )
{
return left += right;
}
class Number
{
Number()
{
value = 1;
};
inline Number operator + (const Number& n) const
{
Number result;
result = value + n.value;
return result;
}
int value;
}
How about:
inline Number operator + (const Number& n) const
While I feel the previous answers are good enough, I believe some clarification is needed.
Operators come (usually) in two flavors
The first being the non-member functions, the second being the member function whose parameter is the "right operand" of the operation and which usually returns the current modified object.
For example, imagine there's an operator § for a class T. It could be written either as a non-member function:
T operator § (const T & lhs, const T & rhs)
{
T result ;
// do the lhs § rhs operation, and puts the result into "result"
return result ;
}
or as a member function:
T & T::operator § (const T & rhs)
{
// do the "this § rhs" operation, and puts the result into "this"
return *this ;
}
or even (very unusually) as another member function:
T T::operator § (const T & rhs) const
{
T result ;
// do the "this § rhs" operation, and puts the result into "result"
return result ;
}
Usually, you should prefer the non-member function, if only because you should not declare it friend. Thus, using non-member non-friend function enhance the encapsulation of your object.
Disclaimer: There are other flavors, but I'm limiting myself to arithmetic operators like +, *, /, -, etc. here, as well as "credible" operator prototypes.
Analyse your use of the operator
In the case of +:
Each operand needs to be constant because a = b + c must not change b, nor c.
You can accumulate +, like in a = b + c + d + e, so temporaries must exist.
T operator § (const T & lhs, const T & rhs)
{
T result ;
// do the lhs § rhs operation, and puts the result into "result"
return result ;
}
In the case of +=:
You know the left operand A (from A += B) will be modified.
You know the left operand A (from A += B) is its own result.
So you should use:
T & T::operator += (const T & rhs)
{
// do the "this § rhs" operation, and puts the result into "this"
return *this ;
}
As always, premature optimization is the root of all evil
I've seen this kind of code in production code so, it does happen:
T & operator + (const T & lhs, const T & rhs)
{
static T result ; // result is STATIC !!!!
// do the lhs + rhs operation, and puts the result into "result"
return result ;
}
The author hoped to economize one temporary. With this kind of code, writing a = b + c + d leads to interesting (and wrong) results.
^_^
Last but not least
I did write a list of operator overloading prototypes on this page. The page is still under construction, but its main use (easy to copy/paste working prototypes) can be quite useful...