operator definition not working right - c++

I am trying to implement a comparison operator but I'm getting the following errors
whole.cpp(384): error C2270: '==' : modifiers not allowed on nonmember functions
whole.cpp(384): error C2805: binary 'operator ==' has too few parameters
whole.cpp(384): error C2274: 'function-style cast' : illegal as right side of '.' operator
I can't seem to pin down the problem though so here is the code
this is the operator implementation in the class
bool operator==(const DateC& p) const
{
return ( DateC::DateC()== p.DateC() );
};
#include <assert.h>
int main(unsigned int argc, char* argv[])
{
DateC f(29,33,11);
DateC::testAdvancesWrap();
};
void DateC::testAdvancesWrap(void)
{
DateC d;
cout << "DateC::testAdvanceWrap()" << endl ;
cout << "*********************" << endl << endl ;
cout << "\tCHECK ADVANCE MULTIPLES:" << endl;
cout << "\t------------------------" << endl;
d.setDay(1);
d.setMonth(12);
d.setYear(1999);
prettyPrint(d);
cout << "ACTION: set date 01-Dec-1999, advance, 31 days, 1 month and 1 year ->" << endl;
d.advance(1,1,31);
assert( d == DateC(1,2,2001) );
cout << "SUCCESS" << endl;
prettyPrint(d);
cout << endl << endl;
}
the rest of the functions working fine it's only the assert()

You can implement comparison operators as member functions or free functions. To implement it as a free function as you are trying to do you need to accept two arguments - the value on the left hand side of = and the value on the right hand side of =. The example below shows how to properly do this.
struct Date
{
int variable_;
};
bool operator==(const Date& lhs, const Date& rhs)
{
return lhs.variable_ == rhs.variable_;
}
To implement the comparison operator as a member function you only need to take one argument which is the value on the right hand size of =. The object owning the comparison operator being executed is the value on the left hand side of =. In this case the operator should be const qualified.
struct Date
{
int variable_;
bool operator==(const Date& rhs) const
{
return variable_ == rhs.variable_;
}
};
In all cases the argument should be taken as a const reference to allow the use of rvalues (temporaries).

Related

Invalid operands to binary expression when using unordered_map?

I'm trying to find if my character hash table contains the first character of a string:
string minWindow(string s, string t) {
unordered_map<char, int> charFinder;
for (int i = 0; i < t.length(); ++i) {
charFinder[t[i]] = 0;
}
cout << charFinder.find(s[0]) == charFinder.end() << endl;
return "hi";
}
But I get this error for some reason. This doesn't make any sense to me. Anyone have any ideas?
Line 8: Char 14: error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'std::unordered_map<char, int, std::hash<char>, std::equal_to<char>, std::allocator<std::pair<const char, int> > >::iterator' (aka '_Node_iterator<std::pair<const char, int>, __constant_iterators::value, __hash_cached::value>'))
cout << charFinder.find(s[1]) == charFinder.end() << endl;
~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/cstddef:124:5:
note: candidate function template not viable: no known conversion from 'std::ostream' (aka 'basic_ostream<char>') to 'std::byte' for 1st argument
operator<<(byte __b, _IntegerType __shift) noexcept
^
I cutoff the rest of the long error message.
Per Operator Precedence, operator<< has a higher precedence than operator==, so your cout expression:
cout << charFinder.find(s[0]) == charFinder.end() << endl;
Is being evaluated as if you had written it like this:
(cout << charFinder.find(s[0])) == (charFinder.end() << endl);
The compiler error is complaining about passing the std::unordered_map itself to operator<<, which is not what you intended. Look at the error message more carefully, that is exactly what it is pointing out. There is no operator<< for std::ostream that takes a std::unordered_map as input.
To fix this, you need to use parenthesis explicitly to tell the compiler what you really want, eg:
cout << (charFinder.find(s[0]) == charFinder.end()) << endl;
Otherwise, use a bool variable instead:
bool notFound = charFinder.find(s[0]) == charFinder.end();
cout << notFound << endl;
In C++20, you can use std::unordered_map::contains() instead:
cout << charFinder.contains(s[0]) << endl;
That being said, since you are not actually using the character counts at all, you should use std::set instead of std::unordered_map, eg:
string minWindow(string s, string t) {
set<char> charFinder;
for (int i = 0; i < t.length(); ++i) {
charFinder.insert(t[i]);
}
//
// alternatively:
// set<char> charFinder(t.begin(), t.end());
cout << (charFinder.find(s[0]) == charFinder.end()) << endl;
//
// alternatively:
// bool notFound = charFinder.find(s[0]) == charFinder.end();
// cout << notFound << endl;
//
// alternatively:
// cout << charFinder.contains(s[0]) << endl;
return "hi";
}
Problem is with this statement :
cout << charFinder.find(s[0]) == charFinder.end() << endl;
stream insertion operator, << has higher precedence than equality operator, ==.
The statement is same as :
((cout << charFinder.find(s[0])) == charFinder.end()) << endl;
The overloaded operator << of std::cout returns a reference to std::cout.
When compiler encounters that you are comparing a std::ostream object (std::cout) with an iterator which is returned by std::unordered_map.end() it issues an error as std::ostream does not have an overloaded operator == to compare itself with an iterator.

C++ - Copy Assignment Operator in Template

I'm trying to overload a copy assignment operator in template struct xpair
template <typename First, typename Second>
struct xpair {
First first{};
Second second{};
xpair(){}
xpair (const First& first, const Second& second):
first(first), second(second) {}
xpair& operator= (const xpair& that) {
cout << "*this = " << *this << " " << "that = " << that << endl;
cout << "use operator = " << endl;
*this = that;
return *this;
}
};
But when I test this code with
using commend = string;
using str_str_pair = xpair<string, string>;
using commend_pair = xpair<commend, str_str_pair>;
commend_pair cmd_pair;
str_str_pair str_pair("a", "1");
commend cmd("comment");
cmd_pair.first = cmd;
cmd_pair.second = str_pair;
It gives me infinite output as
use operator =
*this = {,} that = {a,1}
use operator =
*this = {,} that = {a,1}
use operator =
*this = {,} that = {a,1}
use operator =
*this = {,} that = {a,1}
Why is that?
It gives me infinite output as
Why is that?
Because you've defined the function in terms of itself, see the following code comment.
xpair& operator= (const xpair& that)
{
cout << "*this = " << *this << " " << "that = " << that << endl;
cout << "use operator = " << endl;
// Here you're asking for `this` (i.e., an `xpair` type) to be assigned
// a `that` (i.e., another `xpair` type) using the `operator=` which is
// the function currently being implemented/defined. A function calling
// itself is recursion and there is no stopping condition so it will
// continue infinitely.
*this = that;
return *this;
}
Instead your operation should set the data members of this instance using the data members of that instance.
xpair& operator= (const xpair& that)
{
cout << "*this = " << *this << " " << "that = " << that << endl;
cout << "use operator = " << endl;
first = that.first;
second = that.second;
return *this;
}
Your line
*this = that;
is an assignment as well, taking two arguments. And both are xpair<First,Second>, so it calls the same operator again.
What you would probably like to do is this:
this->first = that.first;
this->second = that.second;
which calls the assignment operators for First and Second.
Your problem is, as others have noted, that your operator= calls your operator=. This results in an infinite recursion.
But, I'll argue for a different implementation:
Add this:
template<class Self,
class=std::enable_if_t<std::is_same<std::decay_t<Self>, xpair>{}>
>
friend auto tieme(Self&& self) {
return std::forward_as_tuple(
std::forward<Self>(self).first,
std::forward<Self>(self).second
);
}
to the body of your pair. The enable_if_t stuff is a bit obscure, but it makes sure this free function will only be invoked on genuine xpairs.
Now your operator= is just:
xpair& operator= (const xpair& that) {
tieme(*this)=tieme(that);
return *this;
}
which is nice, because you don't have to repeat the order of your elements twice over.
But it doesn't stop there.
friend bool operator<(const xpair& lhs, const xpair& rhs) {
return tieme(lhs) < tieme(rhs);
}
the same technique lets you write a bunch of other operators. And anyone who has ever had bugs in < boilerplate will understand that the above is nice.
Move assign?
xpair& operator= (xpair&& that) {
tieme(*this)=tieme(std::move(that));
return *this;
}
swap?
friend void swap(xpair& lhs, xpair& rhs) {
std::swap( tieme(lhs), tieme(rhs) );
}
and it scales -- add more stuff to tieme, and it is auto-handled by all your other methods.

assert() function throwing an error something wrong with the operator

The error I'm getting is
whole.cpp(384): error C2270: '==' : modifiers not allowed on nonmember functions
whole.cpp(384): error C2805: binary 'operator ==' has too few parameters
whole.cpp(384): error C2274: 'function-style cast' : illegal as right side of '.' operator
I can't seem to pin down the problem though so here is the code
this is the operator implementation in the class
bool operator==(const DateC& p) const{return ( DateC::DateC()== p.DateC() );};
#include <assert.h>
int main(unsigned int argc, char* argv[])
{
DateC f(29,33,11);
DateC::testAdvancesWrap();
};
void DateC::testAdvancesWrap(void)
{
DateC d;
cout << "DateC::testAdvanceWrap()" << endl ;
cout << "*********************" << endl << endl ;
cout << "\tCHECK ADVANCE MULTIPLES:" << endl;
cout << "\t------------------------" << endl;
d.setDay(1);
d.setMonth(12);
d.setYear(1999);
prettyPrint(d);
cout << "ACTION: set date 01-Dec-1999, advance, 31 days, 1 month and 1 year ->" << endl;
d.advance(1,1,31);
assert( d == DateC(1,2,2001) );
cout << "SUCCESS" << endl;
prettyPrint(d);
cout << endl << endl;
}
the rest of the functions working fine it's only the assert()
When you create your own classes, if you want to compare them, you need to create operators for them. Let's say you would like to compare 2 instances of a class Person.
A person consist of a string and an int - lastname and height.
We wish to compare people by their height, so we need to tell the compiler how to do it.
An example:
class Person
{
string lastname;
int height;
bool operator == (const Person& p) const
{
return (this->height == p.height);
}
};
EDIT:
I think you misunderstood my example, you can only compare things that the compiler knows how to compare. Your Date implemantation probably has ints, so if you are checking for equality, you have to check all fields.
Use this-> to have access to the other object's fields in the function.

Combining overloaded operators with 'new' object

i'd like to ask something rather difficult for me; I have to make a calendar-type program, but with an overloaded '+=' operator.
So it goes like this:
template<typename T1,typename T2,typename T3> //int,int,int
class T_sort_data{
T1 p1;
T2 p2;
T3 p3;
public:
T_sort_data(){
cout << "\n\t Constructed at [" << this << "]\n";};
/ friend ostream& operator<<(ostream& os,const T_sort_data& obj) // get function
{
os << "\nDay : " << obj.p1 << " \n";
os << "Month : " << obj.p2 << " \n";
os << "Year : " << obj.p3 << " \n";
return os;
}*/
void set_date(){
int dd,mm,yy;
cout << "\n\n\tPlease input the day, the month and the year : \n\n";
cin >> dd >> mm >> yy;
p1 = dd;
p2 = mm;
p3 = yy;
}
// validator here, which works ...
T_sort_data<int,int,int>& operator+=(const T_sort_data<int,int,int>& second)
{
p1+=second.p1;
return *this;
}
friend istream& operator>>(istream& is, T_sort_data& obj) // set function
{
is >> obj.p1;
is >> obj.p2;
is >> obj.p3;
return is;
}
~T_sort_data(){
cout << "\n\t Deconstructed [" << this << "]\n";};
};
int main(){
T_sort_data<int,int,int> * a = new T_sort_data<int,int,int> ;
bool more = true;
string answ;
a->set_date();
//cin >> a; (this doesn't work)
//validator goes here
//a += a; (this, again, doesn't work)
delete a;
return 0;
}
Whenever I make an object using "T_sort_data a;" those operations work fine, but whenever I use "T_sort_data * a = new T_sort_data;"
shit hits the fan.
Can anyone help me with this?
You didn't post exactly what is going wrong so I have to infer that from the code.
The issue that you're running into is that overloaded operators work on instances or references to objects, not on pointers to objects. In the cases where your code doesn't work, you're dealing with pointers to objects. So, in order to use your overloaded operators, you need to dereference the pointer (effectively turning it from a pointer pointing to a value into the value itself) before applying the operator, for example:
cin >> *a;
or
*a += *a;
T_sort_data a is a variable of type T_sort_data.
T_sort_data * a is a variable of type pointer to T_sort_data.
Your overloaded operators expect their operands to be of type T_sort_data, not pointer to T_sort_data. Use the unary * operator to dereference the pointers, so that the operand types are what the operators expect.
This is pretty fundamental. Here's the same thing with int and std::cout: http://codepad.org/N07Xckdy

Compiler error message with cout

I mistyped the error message before. It is fixed now.
I'm currently getting the following compiler error message
error: no match for 'operator<<' in 'std::cout << Collection::operator[](int)(j)'
The code that the compiler is complaining about is
cout << testingSet[j];
Where testingSet is an object of type Collection that has operator[] overloaded to return an object of type Example. Example has a friend function that overloads operator<< for ostream and Example.
note: this actually compiles just fine within Visual Studio; however does not compile using g++.
Here is the implementation of operator<<:
ostream& operator<<(ostream &strm, Example &ex)
{
strm << endl << endl;
strm << "{ ";
map<string, string>::iterator attrib;
for(attrib = ex.attributes.begin(); attrib != ex.attributes.end(); ++attrib)
{
strm << "(" << attrib->first << " = " << attrib->second << "), ";
}
return strm << "} classification = " << (ex.classification ? "true" : "false") << endl;
}
And the operator[]
Example Collection::operator[](int i)
{
return examples[i];
}
Probably your operator should be declared as:
ostream& operator<<(ostream &strm, const Example &ex)
Note the const-reference to Example.
Visual Studio has an extension that allows to bind a reference to a non-const r-value. My guess is that your operator[] returns an r-value.
Anyway, an operator<< should be const as it is not expected to modify the written object.