Hash function errors, c++ - c++

Here's the simple example class with hash function I wrote. Function maybe isn't most efficient one, but quality of hash function isn't relevant to me for now.
#include<iostream>
#include<unordered_set>
using namespace std;
class Class{
private:
int num;
public:
Class(int n){num=n;}
Class(){num=0;}
int getNum(){return num;}
friend bool operator==(const Class &k1, const Class &k2);
};
bool operator==(const Class &k1, const Class &k2){
return(k1.num == k2.num);
}
namespace std {
template <>
struct hash<Class>{
size_t operator()(const Class & c) const
{
return(31+c.getNum()*7);
}
};
}
void main(){
unordered_set<Class> set;
set.insert(Class(5));
set.insert(Class(55));
set.insert(Class(4));
set.insert(Class(123));
set.insert(Class(11));
for(unordered_set<Class>::iterator it = set.begin(); it!=set.end(); it++)
cout<<it->getNum()<< endl;
}
This worked fine when all fields of Class were public, but errors appear in hash function at return(31+c.getNum()*7); on c, because I can't call getNum() function. I don't know if there is any problem if in line size_t operator()(const Class & c) const I remove const, so object c is not const?
Also, in the last line, cout<<it->getNum()<< endl, there is error when accessing getNum() function. I don't know how to iterate over unordered_set set and to print num.

Your operator takes a const class but calls a non-const member function. To fix your issue declare getNum as const since it does not modify the class.
class Class{
private:
int num;
public:
Class(int n) : num(n) {}
Class() : num(0) {}
int getNum() const { return num;}
friend bool operator==(const Class &k1, const Class &k2);
};
In the above example also notice that I used member initializer lists to instantiate member variables. Also change the return type from void to int on main and I recommend either returning 0 or EXIT_SUCCESS from <cstdlib> at the end of main.

Related

How to properly rewrite with templates this C++ code that uses inheritance

I have a C++ code that currently looks like this: there is a class hierarchy to do perform some comparison and a list class that uses it. Which comparison operation to use is determined at runtime based on some schema object. Here is the structure:
class A{
bool doComparison(const string& s1, const string& s2) const=0;
}
class B: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
class C: public A{
bool doComparison(const string& s1, const string& s2) const {
...
}
}
template <class, S>
public FancyList{
shared_ptr<A> z_;
vector<S> v;
FancyList(shared_ptr<A> z) : z_(z);
void DoSmth(){
....
z_->doComparison(arg1, arg2);
}
}
typedef FancyList<string> FancyStringList;
// Determine which comparison to use at runtime
shared_ptr<A> c = nullptr;
switch(type):
case int:
c = make_shared<B>();
break;
case double:
c = make_shared<B>();
break;
FancyStringList l(c);
l.push_back("stuff");
C# used to be my main language so this code seemed ok to me. But I was told that the problem with this approach is that it uses virtual functions so there is a slight overhead in a method call. What is the proper C++-way of reorganizing this code so there is no need to have this class hierarchy and no need to use virtual functions?
Contrary to what you want, the overhead of virtual function is unavoidable because the decision of which actual function is called is made in runtime.
If the decision is always made in runtime, the compiler cannot hard-code the function call into the generated machine code. It has to be a indirect function call: to use a pointer to point to a function, and to dereference the pointer before the function call. Virtual function is just one way to do indirect function call.
Template is a way tell the compiler to generate code during compile-time. All template can do is to not introduce overhead when the decision is made during compile-time. It can't help you remove works that must be done in runtime.
If you are still interested in using template, you may consider having the comparator as a template parameter.
template <class T, class Comparator>
class MyList
{
std::vector<T> vec;
Comparator comp;
public:
void do_thing(const T& a, const T& b)
{
vec.push_back(a);
vec.push_back(b);
bool x = comp(vec[0], vec[1]); // for example
std::cout << x;
}
};
In the comparator class, overload the function call operator.
class Compare1
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs < rhs;
}
};
class Compare2
{
public:
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return lhs.size() < rhs.size();
}
};
int main()
{
MyList<std::string, Compare1> myli1;
myli1.do_thing("a", "b");
MyList<std::string, Compare2> myli2;
myli2.do_thing("c", "d");
}
You can even hide indirect function call behind comparator class. But it does not remove the overhead.
class A
{
public:
virtual bool doComparison(const std::string& s1, const std::string& s2) const=0;
virtual ~A() = default;
};
class PolymorphicComparator
{
private:
std::shared_ptr<A> comp;
public:
PolymorphicComp(std::shared_ptr<A> c) : comp(c) {}
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return comp->doComparison(lhs, rhs);
}
};

why does one code compiles and the other fails?

This code complies:
template <class T>
class A {};
void main () {
A<int> a;
vector<A<int>> vec;
vec.push_back(a);
}
but this doesn't:
void main () {
SharedPointer<int> sp;
vector<SharedPointer<int>> vec;
vec.push_back(sp);
}
I get this error:
error C2558: class 'SharedPointer' : no copy constructor available
or copy constructor is declared 'explicit'
SharedPointer header: (all methodes are implemented in the header)
#include <iostream>
#include "Myexception.h"
using namespace std;
#pragma once
template<class T>
class SharedPointer {
T* ob;
int* refcount;
bool shareable;
int refdown();
int refup();
void markUnshareable();
public:
virtual ~SharedPointer();
SharedPointer():shareable(true);
SharedPointer(T pointee):shareable(true);
SharedPointer(SharedPointer<T>& sp);
SharedPointer operator=(const SharedPointer<T>& sp);
bool operator==(const SharedPointer<T>& sp);
const T& operator[](const int idx) const;
T& operator[](const int idx);
T* operator->() const;
T& operator*() const;
void setOb(T pointee);
const T& getOb() const;
int getRefcount();
bool isShareable();
bool isShared();
};
The problem is that the copy constructor:
SharedPointer(SharedPointer<T>& sp);
can't only be used to copy a const pointer. Add the missing const and all should be fine:
SharedPointer(const SharedPointer& sp); // <T> is harmless, but unnecessary
(You'll also have to fix the syntax errors in the constructor definitions, and you should change the return type of main to int. Removing using namespace std; would also be a good idea.)
Your copy constructor declared
SharedPointer(SharedPointer<T>& sp);
should look like :
SharedPointer(const SharedPointer<T>& sp);
so the compiler will find the missing copy constructor

Sorting a vector in C++ by accessing a private member

I'm working on a project and I have to sort a vector, but I'm facing some difficulties.
class CService {
private:
string m_strSeller;
public:
// Other stuff.
};
class CAnalizeTime : public CService {
private:
void sortSellerVector () {
vector<CService>m_vData;
m_vData.push_back(m_strSeller);
sort(m_vData.begin(), m_vData.end());
}
};
I'm getting 2 errors on my void sortSellerVector() function:
Cannot access private member declared in class 'CService'
Cannot convert from 'class std::basic_string,class std::allocator >' to 'const class CService'
My questions are:
How do you access a private member from another class?
What exactly does the second error mean? I don't understand it.
To be able to sort a vector<CService>, the easiest way is to just give CService an operator< overload that std::sort can use to sort the elements. Of course, this operator< overload will have access to m_strSeller if it is a member function:
class CService {
private:
string m_strSeller;
public:
bool operator<(const CService& other) const
{
return m_strSeller < other.m_strSeller;
}
/////..... (other stuff)
};
Then you can just do:
vector<CService> vData;
// Push some CServices into the vector
sort(vData.begin(), vData.end());
An alternative method is to have a comparison function that you give to std::sort to use. You can make it a friend of CService so that it can access the private member:
class CService {
private:
string m_strSeller;
public:
friend bool compare(const CService&, const CService&);
/////..... (other stuff)
};
bool compare(const CService& a, const CService& b)
{
return a.m_strSeller < b.m_strSeller;
}
Which you then use like so:
vector<CService> vData;
// Push some CServices into the vector
sort(vData.begin(), vData.end(), compare);

Why i need to use the const function in the Less Traits

why i need to use the const function in the less traits?
for example, why i must use const in Age or ID member function.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <string>
#include <set>
using namespace std;
class Person
{
public:
Person(int id, string name, int age):m_iID(id), m_strName(name), m_iAge(age){};
int Age() const {return m_iAge;}
int ID() const {return m_iID;}
void Display();
friend ostream& operator<<(ostream& out, Person& person);
private:
int m_iID;
string m_strName;
int m_iAge;
};
void Person::Display()
{
cout<<m_iID<<" "<<m_strName<<" "<<m_iAge<<endl;
}
ostream& operator<< (ostream& out, Person& person)
{
out<<person.m_iID<<" "<<person.m_strName<<" "<<person.m_iAge<<endl;
return out;
}
int SumPersonAge(int iSumAge, Person& person)
{
return iSumAge + person.Age();
}
template <typename Type>
void Display(Type t1)
{
cout<<t1<<endl;
}
class LessPerson
{
public:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
int main()
{
set<Person, LessPerson> s1;
Person p1(1234, "Roger", 23);
Person p2(1235, "Razor", 24);
s1.insert(p1);
s1.insert(p2);
for_each(s1.begin(), s1.end(), Display<Person>);
}
if i remove the const the keyword in Age or ID function, the compiler will report me Error cannot convert 'this' pointer from 'const Person' to 'Person &'.
The answer is that the set will pass two const reference to Person objects to your comparator, and you cannot call a non-const function on a const variable.
You might be surprised as there seems not to be any const in the declaration of the functor:
struct LessPerson
{
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
};
But there is, it is just not explicit in the code. Inside the set implementation there are two const Person& references (call them r1, r2) and a LessPerson comparator (call it compare) and the code does something in the lines of if ( comparator(r1,r2) ). The compiler finds the templated operator() and tries to infer the types ending up with the type substitution: Type == const Person.
Why does the set use const references rather than plain modifiable references? Well, that is a different issue. The set is implemented as a sorted balanced tree, with each node containing the key. Now because a change in the key would break the order invariant, the keys are themselves const objects, ensuring that you cannot break the invariants.
That const keyword means that the function does not modify its object, this. Only const functions may be called from const objects. So, the compiler is telling you that you are trying to call a non-const member function from a const object.
You appear to be avoiding the const keyword, but it creeps in when the library calls your template function:
template <typename Type>
bool operator()(Type& t1, Type& t2)
{
return t1.ID() < t2.ID();
}
Type is passed as const Person.
const is not easy to get rid of without cheating, and it will always creep in. It's better to go with the flow and add const everywhere you take a reference that doesn't change an object (which is most of them).
Because the type passed to LessPerson is const Person.
So basically, LessPerson is roughly
class LessPerson   
{
public:
bool operator()(const Person& t1, const Person& t2)
{
return t1.ID() < t2.ID();
}
};
You can't call non-const methods on const objects. It's a rule of C++.

Why isn't stl compare function a member?

Just idly curious why the compare function for stl::sort can't be a static member?
I have a small little helper class foo that is declared and defined in a header, but now I have to create a foo.cpp file for the implementation of cmp() so it isn't multiply defined.
I also have to think of a suitably decorated name so fooCmp() doesn't clash with any other cmp().
Because it has no access to any member variables any compare operation that needs access to some other value (eg. sort by distance from foo.bar) needs the complex bind2nd call.
I am not sure what you are complaining about:
std::sort(begin,end) // use operator<
std::sort(begin,end,order) // Where order is a functor
So order can be:
A function
A static member function
Or an object that behaves like a function.
The following works for me:
class X
{
public: static bool diff(X const& lhs,X const& rhs) { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end(),&X::diff);
}
But if the class has some natural ordering then why not just define the operator< for the class. This will allow you the access to the members and will behave nicely for most of the standard containers/algorithms that need to define an ordering.
class X
{
public: bool operator<(X const& rhs) const { return true;}
};
int main()
{
std::vector<X> a;
std::sort(a.begin(),a.end());
}
If you're concerned with a multiply defined compare function, try declaring the function with static linkage. Then the scope of the function does not extend past the compilation unit where it is found.
That said, your compare "function" need not be a function at all, but can instead be a function object. A function object is very much like a function but is implemented as an operator() that takes the appropriate parameters within a regular class. Since it's a regular class, you can pass constructor parameters to the class.
Here is a simple example:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class comparator {
public:
bool operator()(int a, int b) {
return a < b;
}
};
int main(int, char *[])
{
vector<int> a;
a.push_back(1);
a.push_back(3);
a.push_back(2);
sort(a.begin(), a.end(), comparator());
cout << a << endl;
}
actually sounds like the function was
declared in the class,
defined in the header but outside the class without inline linkage
ie something like:
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
bool foo::compare(const foo& lhs,const foo& rhs){
...
}
instead of
class foo{
public:
static bool compare(const foo& lhs,const foo& rhs);
...
};
inline bool foo::compare(const foo& lhs,const foo& rhs){
...
}
the first of which will cause the function to be defined in every compilation unit that
#includes "foo.h"