No match for operator== in generic function - c++

I have the code below, I'm attempting to write a generic function which takes 2 iterators and an object and checks for any occurrences and returns the number of occurrences.
below my simple class
class person{
string name;
int age;
public:
person(string n, int a): name(n), age(a) {}
bool operator==(person &p);
};
bool person::operator==(person &p){
return (name == p.name && age == p.age);
}
Below is the generic function
template<typename Iter, typename Obj>
int count_obj(Iter iter1, Iter iter2, Obj &obj){
int count = 0;
for (; iter1 != iter2; iter1++){
if((*iter1) == obj)
count += 1;
}
return count;
}
my main:
int main(){
vector<person *> myp;
person a("ted", 21); person b("sun", 100); person c("ted", 21);
myp.push_back(&a);myp.push_back(&b);myp.push_back(&c);
cout<< "occurences for person objects " << count_obj(myp.begin(), myp.end(), a) << '\n';
}
Full error
3b.cc: In function ‘int count_obj(Iter, Iter, Obj&) [with Iter = __gnu_cxx::__normal_iterator<person**, std::vector<person*> >, Obj = person]’:
3b.cc:61:79: instantiated from here
3b.cc:42:3: error: no match for ‘operator==’ in ‘iter1.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = person**, _Container = std::vector<person*>, __gnu_cxx::__normal_iterator<_Iterator, _Container>::reference = person*&]() == obj’
make: *** [3b] Error 1
I cant seem to figure out I'm getting this error.

You have a vector of person *, and you're trying to compare them against a person. You will need to modify the line of code in count_obj to be either:
if (*(*iter1) == obj)
or:
if ((*iter1) == &obj)
depending on whether you wish to compare pointers or objects.
[Note: Are you aware of the std::count function in the standard library?]
[Note (2): As mentioned in another answer, you should probably read up on "const correctness". You should declare your operator== as const, and it should take a const reference as an argument.]
[Note (3): Storing raw pointers in a container is often a bad idea. For instance, are you aware that you effectively have a memory leak?]

Related

how to make find() function using vector (class)

there is class like as
class C_Service
{
public :
C_Service(); {memset(this, 0, sizeof(*this));}
C_Service(int type, int idx) {memset(this, 0, sizeof(*this)); this->type = type; this->idx = idx;}
bool operator==(const C_Service& svc) const { return (this->type == svc.type && this->idx == svc.idx);}
word type;
word idx;
dword aId;
dword bId;
char* name;
};
I used test code as below,
void vec_find(int type, int idx)
{
vector<C_Service*> vec;
// added several items in vector vec
...
vector<C_Service*>::iterator iter;
C_Service cSvc(type, idx);
iter = find(vec.begin(), vec.end(), &cSvc);
C_Service* findsvc = *iter;
if(findsvc)
printf("FOUND : type(%d), idx(%d), name(%s)\n", findsvc->type, findsvc->idx, findsvc->name);
else
printf("Not FOUND!!\n");
}
then, it give "Not FOUND!!" even set correct value.
I found something wrong and trying change..
iter = find(vec.begin(), vec.end(), &cSvc);
to
iter = find(vec.begin(), vec.end(), cSvc);
remove "&"
then it give compile error message
/libcxx/algorithm: In instantiation of '_InputIterator
std::__1::find(_InputIterator, _InputIterator, const _Tp&) [with
_InputIterator = std::__1::__wrap_iter; _Tp = C_Service]':
no match for 'operator==' (operand types are 'C_Service*' and 'const
C_Service')
I searched that when I use find() function in Container, It can use operator==
but, I can't get a goal..T.T
What is my fault?
The problem is that your vec is a vector of pointers, not a vector of C_Service objects.
Thus
find(vec.begin(), vec.end(), &cSvc)
checks whether the address of the cSvc variable is contained within vec (which it's not because you just created cSvc so it can't be referenced from anywhere else). It does not use your operator== at all, it just compares pointers.
To fix it, you can either change vec to be a std::vector<C_Service> and do
find(vec.begin(), vec.end(), cSvc)
or pass a custom predicate to find_if, where you can dereference your pointers manually:
find_if(vec.begin(), vec.end(), [&](const C_Service *p) { return *p == cSvc; })

I am confused about constant, constant references, references to constants, ... (including example code)

I am trying to write a graph data structure implementation that I feel satisfied with. (Maintain adjacency lists as sets instead of linked lists.) Anyways, I tried to use references and iterators and wrote this:
#include <iostream>
#include <string>
#include <set>
#include <stack>
class Vertex {
std::string name;
std::set<Vertex> edges;
public:
Vertex(std::string name) : name(name) {}
std::string vertexName() const {
return name;
}
std::set<Vertex> outEdges() const {
return edges;
}
void addEdge(const Vertex& other) {
edges.insert(other);
}
void removeEdge(const Vertex& other) {
edges.erase(other);
}
int outDegree() {
return edges.size();
}
};
bool operator<(const Vertex& v1, const Vertex& v2) {
return (v1.vertexName().compare(v2.vertexName()) < 0);
}
void DFS(const Vertex& v) {
std::stack<Vertex*> stack;
std::set<Vertex*> visited;
stack.push(&v); // error1
visited.insert(&v); // error2
while (!stack.empty()) {
Vertex* vert_ptr = stack.top();
stack.pop();
std::cout << vert_ptr->vertexName() << std::endl;
//
for (std::set<Vertex>::iterator iter = vert_ptr->outEdges().begin(); iter != vert_ptr->outEdges().end(); iter++) {
if (visited.find(&(*iter)) != visited.end()) { // error3
stack.push(&(*iter)); // error4
visited.insert(&(*iter)); // error5
}
}
}
}
int main() {
Vertex a = Vertex("a");
Vertex b = Vertex("b");
Vertex c = Vertex("c");
DFS(a);
getchar();
return 0;
}
I am getting the following errors:
error1: E0304 no instance of overloaded function "std::stack<_Ty, _Container>::push [with _Ty=Vertex *, _Container=std::deque<Vertex *, std::allocator<Vertex *>>]" matches the argument list
error2: E0304 no instance of overloaded function "std::set<_Kty, _Pr, _Alloc>::insert [with _Kty=Vertex *, _Pr=std::less<Vertex *>, _Alloc=std::allocator<Vertex *>]" matches the argument list
error3: E0304 no instance of overloaded function "std::set<_Kty, _Pr, _Alloc>::find [with _Kty=Vertex *, _Pr=std::less<Vertex *>, _Alloc=std::allocator<Vertex *>]" matches the argument list
error4: E0304 no instance of overloaded function "std::stack<_Ty, _Container>::push [with _Ty=Vertex *, _Container=std::deque<Vertex *, std::allocator<Vertex *>>]" matches the argument list
error5: E0304 no instance of overloaded function "std::set<_Kty, _Pr, _Alloc>::insert [with _Kty=Vertex *, _Pr=std::less<Vertex *>, _Alloc=std::allocator<Vertex *>]" matches the argument list
I am realizing that I do not understand references as well as I thought I did. I used google, and the hits I got reiterate what I understand about references, but do not touch on the part I do not understand (which is causing those errors).
I also dereferenced the iterators, and then used & to get the addresses of the actual objects the iterators are pointing to, and do not know if I am misunderstanding the way iterators work, or if it is just a problem with references.
I would appreciate it if someone could point me towards a good reference on all of this. :(
In your case void DFS(const Vertex& v) v is a reference to a var which is constant. In other words, you promised that the function will not modify the object.
std::stack<Vertex*> stack;
std::set<Vertex*> visited;
The above are containers of pointers to an object, which is not a constant and therefore is modifiable.
Here you are trying to violate an agreement. You are trying to allocate a pointer to a constant object v in a container which is intended for pointers to modifiable objects. If this is would have been allowed, you would be able to modify the value referenced by v through the pointer. So, it is not allowed and the compiler produces an error here.
stack.push(&v); // error1
visited.insert(&v); // error2
so, you needed to declare containers with pointers to the constants:
std::stack<const Vertex*> stack;
std::set<const Vertex*> visited;
now, the visited.find(&(*iter)) has to do with the implementation of the set::iterator. Apparently the value returned by operator '*' referenced a constant value, causing another conversion attempt from 'const' to non-const.
So, declaring stack and visited with const Vertex * argument should solve your compilation issues.

Overloading operator and modifiyng string

I am learning about operator overlaoding. I have created simple class to test it.
class Beer{
public:
Beer(int oner , int twor , string name){
this -> one = oner;
this -> two = twor;
this -> name = name;
};
int getOne(){
return this -> one;
};
int getTwo(){
return this -> two;
};
string getName(){
return this -> name;
};
Beer operator + (const Beer &a)const {
return Beer(5,two+a.two,"firstName");
};
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
private:
int one;
int two;
string name;
};
I am trying to figure out , how to midify the string with overloaded operand. My function i declared
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
Throws error about passing const string.
I tried using
Beer operator + ( const string *a)const {
swap(this -> name , this -> name + " " + a);
return *this;
};
Which complained about one being cosnst string , and secon one being basic string.
The idea is simple.
Beer one ( 5, 6, "one")
one + "two"
// one.name = "one two"
What is the right way how to do it?
// error with swap
error: no matching function for call to 'swap(const string&, std::basic_string<char>)'|
// erro with string
passing 'const string {aka const std::basic_string<char>}' as 'this' argument of 'std::basic_string<_CharT, _Traits, _Alloc>& std::basic_string<_CharT, _Traits, _Alloc>::operator=(std::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' discards qualifiers [-fpermissive]|
Comments:
Don't include the entire std namespace. You're likely to run into nasty name clashes with your own code. At most, use the symbols you need explicitly, e.g. using std::string;.
Unless you need a copy of a value to modify, pass large objects like std::string by const reference. When you declare a parameter as having a value type std::string, you receive a copy of the string, and that's expensive unless you need a copy to modify inside of your function.
This is a long-standing problem with the C++ standard: an implementation detail like this, that should be irrelevant to the user of the function, leaks into the interface (the declaration of the function). Still, when having a copy makes sense, let the compiler give you one without having to type as much. Thus:
// prefer this
std::string fooize(std::string foo) {
assert(foo.size() > 0);
foo.insert(1, "foo");
return foo;
}
// over this
std::string fooize(const std::string & bar) {
assert(bar.size() > 0);
auto foo = bar;
foo.insert(1, "foo");
return foo;
}
Use an initializer list, you then won't need to do silly name gymnastics (you had oner, twor names:
Beer(int one, int two, const std::string & name) :
one(one),
two(two),
name(name)
{}
Declare read-only accessors const:
int getOne() const { return one; }
Return large values like strings by const reference; the user code will likely have the compiler help out with making a copy when needed automatically:
const std::string & getName() const { return name; }
// use:
Beer beer{0,0,""};
std::cout << (beer.getName() + "!") << std::endl; // makes a copy of name as needed
In the + operator taking a string, you're supposed to return a new object, not modify this. You pretty much should do it the way the other operator + you have did it.
Beer operator +(const std::string & a) const {
return Beer(one, two, name + " " + a);
};
If you want to modify your object, you want operator +=:
Beer & operator+=(const std::string & a) {
name += " ";
name += a;
return *this;
}
Even though your class was designed to experiment with operators, you should always consider whether the operators make life easier or not. For example, you class has three members. It's not immediately apparent which of these members would be operated on, unless it was otherwise clear from the class's semantics. It'd be much clearer to have methods named addToOne, addToTwo, and appendToName, for example, instead of operator(s), or simply letting the user set the member through setters, like setOne(int one) { this->one = one; }. The user would then simply do beer.setOne(beer.getOne() + 2);.
Consider naming getters without the get prefix, e.g.
class Beer {
int m_one;
public int one() const { reeturn m_one; }
};
It's less typing for the user. The standard library, as well as large libraries like boost and Qt follow this convention, e.g. you have std::string::size(), not std::string::getSize(), etc.
Beer operator + (string a)const {
this -> name = this -> name +" "+a;
};
You should not change the contents of the object who's + operator is beeing called, afterall if you perform A = B + C, the contents of B should not change. The compiler is correctly informing you about this because it is a const function.
Rather create a temp object to hold the 'sum' and return it.
Beer operator + (string a)const {
return Beer(one, two, name + " " + a);
};
In your operator+() here:
Beer operator+( string a ) const
{
this->name = this->name + " " + a;
};
the const on the function signature is a guarantee to the compiler that when the function is invoked, you won't change the data in the object, yet you change the data in the object.

base operand has non pointer type g++ compiler error

In the following code, i am getting error:
city.cc: In member function ‘std::vector<std::basic_string<char> > MyCity::get_neighbours()’:
city.cc:25:42: error: base operand of ‘->’ has non-pointer type ‘std::pair<MyCity*, double>’
In file included from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_algobase.h:65:0,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/char_traits.h:41,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ios:41,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ostream:40,
from /depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/iostream:40,
from city.cc:1:
/depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_pair.h: In instantiation of ‘std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::basic_string<char>; _U2 = double; _T1 = MyCity*; _T2 = double]’:
city.cc:18:50: required from here
/depotbld/RHEL5.5/gcc-4.7.2/bin/../lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/stl_pair.h:111:39: error: cannot convert ‘const std::basic_string<char>’ to ‘MyCity*’ in initialization
.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class MyCity {
string name;
std::vector<pair<MyCity*,double> > neighbours;
public:
MyCity()
{
// neighbours.clear();
}
MyCity(string s, string s1, double d)
{
name = s;
neighbours.push_back(std::make_pair(s1,d));
}
std::vector<string> get_neighbours( )
{
std::vector<string> names;
for (size_t i = 0; i< neighbours.size(); ++i)
{
names.push_back(neighbours[i]->first->get_name());
}
return names;
}
};
class MyState {
vector<MyCity*> cities;
string name;
public:
MyState() { }
MyState(string s) {
name =s;
}
bool add_city(string name, string neigh, double d)
{
MyCity* c = new MyCity(name,neigh,d);
cities.push_back(c);
return true;
}
};
Do not dereference the std::pair as it is not a pointer.
std::vector<string> get_neighbours( )
{
std::vector<string> names;
for (size_t i = 0; i< neighbours.size(); ++i)
names.push_back(neighbours[i].first->get_name());
return names;
}
You also have a problem in your constructor, the std::make_pair(s1, d) will return a std::pair<std::string, double> so it cannot be pushed back to you neighbours vector.
Try something like that:
MyCtiy(string s)
:name(s)
{
}
MyCity(string s, string s1, double d)
:name(s)
{
created_neighbours.emplace_back(new neighbour(s1));
MyCity* city = created_neighbours.back().get();
neighbours.push_back(std::make_pair(city, d));
city->addNeighbour(this, d);
}
private:
std::vector<std::unique_ptr<MyCity>> created_neighbours;
void addNeighbour(MyCity* city, double d)
{
neighbours.push_back(std::make_pair(city, d));
}
Note: you can strip the addNeighbourd part if you don't want the association to be many-to-many.
Edit: Fix the addNeighbour to give a MyCity pointer. Created a created_neighbours collection to store (and free) created neighbours.
3 mistakes can be found in your code. Please find and correct the following 2 lines in your code
neighbours.push_back(std::make_pair(some_pointer_to_the_MyCity_object,d));
names.push_back(neighbours[i].first->get_name());
And you have to implement the get_name() function in MyCity class
Now it should be compiled

subscript operators for class with std::map member variable

I am trying to make a class that wraps std::map and does checking to make sure the keys are one the of approved valid strings, and also initializes the map to have default values for all the approved valid strings. I am having issues getting the subscript operator to work, specifically the const version of it.
Here is my class prototyping code:
#include <set>
#include <string>
#include <map>
class foo {
public:
foo() {}
const double & operator[](const std::string key) const {
return data[key];
}
private:
static const std::set<std::string> validkeys;
std::map<std::string, double> data;
};
const std::set<std::string> foo::validkeys = {"foo1", "foo2"};
When I compile this (using g++ with -std=c++0x), I get this compilation error:
|| /home/luke/tmp/testmap.cc: In member function 'double& foo::operator[](std::string) const':
testmap.cc|10 col 22 error| passing 'const std::map<std::basic_string<char>, double>' as
'this' argument of 'mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const
key_type&) [with _Key = std::basic_string<char>, _Tp = double, _Compare =
std::less<std::basic_string<char> >, _Alloc = std::allocator<std::pair<const
std::basic_string<char>, double> >, mapped_type = double, key_type =
std::basic_string<char>]' discards qualifiers
Nothing I do seems to fix this. I have tried
making validkeys a std::set and data std::map
using const char * instead of string
returning const double or double instead of const double &
using list and vector instead of set to store the validkeys
I don't know if I'm even approaching this problem correctly so if there is some other simple way to create a class that allows this kind of functionality:
foo a;
a["foo2"] = a["foo1"] = 5.0;
// This would raise a std::runtime_error because I would be checking that
// "foo3" isn't in validkeys
a["foo3"] = 4.0;
Any suggestions greatly appreciated.
SOLUTION
The following works exactly how I want it to, I even have a basic exception when you try to set or get a key that isn't in the set of valid keys:
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <stdexcept>
class myfooexception : public std::runtime_error
{
public:
myfooexception(const std::string & s)
: std::runtime_error(s + " is not a valid key.") {}
};
class foo {
public:
foo() {
for (std::set<std::string>::iterator it = validkeys.begin();
it != validkeys.end();
++it) {
data[*it] = 0.0;
}
}
const double & operator[](const std::string & key) const {
if (data.find(key) == data.end()) {
throw myfooexception(key);
} else {
return data.find(key)->second;
}
}
double & operator[](const std::string & key) {
if (data.find(key) == data.end()) {
throw myfooexception(key);
} else {
return data[key];
}
}
private:
static const std::set<std::string> validkeys;
std::map<std::string, double> data;
};
const std::set<std::string> foo::validkeys = {"foo1", "foo2"};
int main(void)
{
foo a;
a["foo1"] = 2.0;
a["foo1"] = a["foo2"] = 1.5;
// a["foo3"] = 2.3; // raises exception: foo3 is is not a valid key
const foo b;
std::cout << b["foo1"]; // should be ok
// b["foo1"] = 5.0; // compliation error, as expected: b is const.
return 0;
}
The operator [] is not declared const in the std::map, because the operator [] also inserts a new element when the key is not found and returns a reference to its mapped value. You can use the map::find method instead of map::operator[] if you want your operator[] to be const.
The subscript operator for std::map is non-const as it inserts a new element if one does not yet exist. If you want your map to have a const operator[], you need to write one that uses map::find() and tests against map::end(), handling the error case.
you are trying to modify a const object!!
please remove the const of set.const members cannot be modified once they are initialised.
You are trying to assign to the std::map but your function is declared const and also returning const. Remove both const and it should work.