I am working on program in which I am require to use a priority queue. From my understanding the priority queue sorts the queue automatically from largest to smallest elements. I have create a simple priority queue of objects(nodes) that have a name and id number. I am trying to access the first object in the queue so I figured I could just use the "front" member function. This works when I use the standard queue but when I use a priority queue I get the error
error: 'class std::priority_queue' has no member named 'front'
I tried using "top" as well but then I get the error
error: passing 'const value_type (aka const node)' as 'this' argument
of 'void::display()' discards qualifiers [-fpermissive]
here is my code:
#include <iostream>
#include <queue>
using namespace std;
struct node
{
node(char n, int i) { name = n; id = i; }
void display() { cout << "name: " << name << " id : " << id << endl; }
friend bool operator < (node a, node b) { return a.id < b.id; }
private:
char name;
int id;
};
int main()
{
queue<node> myqueue; // Actually want a priority_queue<node>
myqueue.push(node('a',5));
myqueue.push(node('b',9));
myqueue.push(node('c',7));
myqueue.front().display(); // Error when using the type I want, even if I call top() instead
}
I will point out again that if I use queue instead of priority queue the code works. How do I access the front of a priority queue?
Your error is that .display() is not a constant member-function.
It should be:
void display() const { std::cout << "name: " << name << " id : " << id << '\n';}
As an aside, only use std::endl if explicitly flushing might be neccessary, as it flushes all hope of good performance down the drain.
Also read: Why is "using namespace std" considered bad practice?
Firstly, std::priority_queue::front does not exist. We just can't invoke something doesn't exist.
Secondly, be const-correct. Declare your member functions const.
void display() const
{...}
This is because the return type of std::priority_queue::top is a const reference. Via a const reference (and const value), only const member functions can be used. Inside a const member function, the object cannot be modified, which is the meaning of being const.
std::priority_queue::front does not exist.
Use
std::priority_queue::top
And yes, function display() should be const as mentioned by fellow member :)
void display() const { std::cout << "name: " << name << " id : " << id << '\n';}
Related
I have a class called CoffeeShop and another class called user. i want to pass a function from the class CoffeeShop to the user class but i have an error, what i tried to do is
User class:
class user {
public:
function<void (string)> fun;
string name;
void order_coffee() {
fun(name);
}
};
then the coffeeshop class
class CoffeeShop {
public:
mutex mtx;
void Make_Coffee(string name) {
cout << "in queue: " << name << endl;
unique_lock<mutex> lock(mtx);
cout << "welcome,order in process, " << name << endl;
this_thread::sleep_for(chrono::seconds(4));
cout << "good bye, " << name << endl;
lock.unlock();
}
void assign() {
user a;
a.fun = CoffeeShop::Make_Coffee;
a.name = "amr kamal";
thread th1(&user::order_coffee, a);
user b;
b.fun = a.fun;
b.name = "hadeer";
thread th2(&user::order_coffee, b);
th2.join();
th1.join();
}
};
I use the function assigned to start running the function, what i want to do is to let the users use the make_coffee function and wait in the queue and it process 1 by 1, i want to be able to let the users access the function.
i use the class as following in the main
int main() {
CoffeeShop coffeeShop;
coffeeShop.assign();
}
the Error i got is on assign the user make_coffee function
error C2679: binary '=': no operator found which takes a right-hand operand of type 'void (__cdecl CoffeeShop::* )(std::string)' (or there is no acceptable conversion)
You have two options
Wrap it in a lambda a.fun = [this](string line) {this->Make_Coffee(line);};
Use std::mem_fun
The problem you are facing is that std::function needs to know about this. Also Why is "using namespace std;" considered bad practice?
In c++, the changes done to the argument inside a function aren't reflected in the actual variable if
the return value of function is void, but that's not the case with the member functions where we can
see the changes happening permanently.
#include<iostream>
using namespace std;
class Student {
public:
int age;
float marks;
Student()
{
cout << "call by default";
}
void ageInc()
{
age = age + 1;
}
};
int main()
{
Student s;
s.age = 34;
cout << s.age << endl;
s.ageInc();
cout << s.age << endl;
return 0;
}
In c++, the changes done to the argument inside a function aren't reflected in the actual variable if the return value of function is void
Changes to an argument's value has nothing at all to do with a function's return type. A void function can quite easily make changes to its arguments. Whether or not those changes are reflected back to the caller has to do with whether the argument is passed by pointer/reference or not.
but that's not the case with the member functions where we can see the changes happening permanently.
A non-static class method receives a hidden this pointer to the object it is being called on. When the method accesses a non-static member of its owning class, it is using that this pointer to access the member. So any changes made to the member are done directly to the mmeber.
Your example is roughly equivalent to the following behind the scenes:
#include <iostream>
using namespace std;
struct Student {
int age;
float marks;
};
Student_ctr(Student* const this)
{
cout << "call by default";
}
Student_dtr(Student* const this) {}
void Student_ageInc(Student* const this)
{
this->age = this->age + 1;
}
int main()
{
Student s;
Student_ctr(&s);
s.age = 34;
cout << s.age << endl;
Student_ageInc(&s);
cout << s.age << endl;
Student_dtr(&s);
return 0;
}
Because you're not changing an argument. Your example function takes no arguments. You're changing a member variable.
You could think of all members of the object as being automatic passed-by-reference parameters, but this isn't how C++ encourages you to think of them.
My program is not compiling and keeps outputing the same error "non-lvalue in assignment." I've tried looking around the internet to why this is happening but I can't seem to find anything. I would really appreciate some input.
#include <iostream>
using namespace std;
class Class
{
public:
Class()
{
Var=0;
}
private:
int Var;
friend void Friend(Class &object);
};
void Friend(Class &object)
{
&object.Var=99;
cout << &object.Var << endl;
}
int main()
{
Class testobject;
Friend(testobject);
}
You won't need the & inside the function
The problem is this line &object.Var=99; You taking the address of object and than accessing .Var, this cant work.
Seems you missunderstood references, you dont have to dereference them (unlike pointer).
Change your function to this:
void Friend(Class &object)
{
object.Var=99;
cout << object.Var << endl;
}
Change the function definition to
void Friend(Class &object)
{
object.Var=99;
cout << object.Var << endl;
}
The reason of the error is described in the following quote of the C++ Standard
if the type of the expression is T, the result has type “pointer to T”
and is a prvalue
Replace &object.Var=99; with object.Var=99; and cout << &object.Var << endl; with cout << object.Var << endl;
When passing an argument, & denotes that you receive the variable as a reference.
void Friend(Class &object) means you get the reference of testobject in object.
&object.Var implies address of object.Var. You cannot assign to that. Hence the error non-lvalue in assignment.
Take this example code
#include <iostream>
using namespace std;
class Address
{
public:
mutable unsigned key;
Address() : key(0) {};
Address(int a) : key(a) {};
// const Address but compiler lets us modify it anyway!
Address(const Address &n) : key(++n.key) {};
void showKey() { cout << "key is " << key << endl;}
void modifyKey(int k) { key = k;}
};
int main()
{
cout << "Address a " << endl;
Address a;
a.showKey();
cout << "Address b " << endl;
Address b(a);
b.showKey();
if (b.key == a .key)
cerr << "Wow the compiler doesn't care about const correctness" << endl;
return 0;
}
The copy constructor of the Address class says that n if a reference to a constant Address object. Therefore I expect modifications to the object referenced by n to be disallowed. It seems that directly manipulating n's fields is allowed by the compiler. However I did notice if I add a non const method to Address and call it on n inside the copy constructor (e.g. n.myNonConstMethod()) the compiler will complain.
I am surprised that this code compiles (I've tried g++ and clang++ and they compile with out errors or warnings). Have I misunderstood the use of const (it wouldn't be the first time!) or are these compiler bugs?
Pulled from MSDN:
This keyword [mutable] can only be applied to non-static and non-const data members of a class. If a data member is declared mutable, then it is legal to assign a value to this data member from a const member function.
I'd need to write a class with an overloaded operator [] which has different behavior when the operator [] is used to read or write data.
To give a practical example of what I want to achieve, let's say I have to write the implementation of a class named PhoneBook which can be used in the following way:
PhoneBook phoneBook(999999); // 999999 is the default number which should be
// used when calling someone who is not in the phone book
phoneBook["Paul"] = 234657; // adds Paul's number
phoneBook["John"] = 340156; // adds John's number
// next line should print Paul's number 234657
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
// next line should print John's number 340156
cout << "To call John dial " << phoneBook["John"] << endl;
// next line should print 999999 because Frank is not in the phone book
cout << "To call Frank dial " << phoneBook["Frank"] << endl;
The problem is in the fact that when using
phoneBook["Frank"]
I don't want to add an entry in the phone book for Frank, otherwise a solution based on std::map would be easy to implement.
I did not find on the web any standard way to achieve this so
after some thinking I came up with the following solution in which the operator [] returns a "temporary object" named PhoneNumber. PhoneNumber is then used to distinguish between read/write operations:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class PhoneBook{
private:
map<string, int> data_; // stores phone numbers
int defaultNumber_; // default number returned when no matching name is found
public:
PhoneBook(int defaultNumber) :
defaultNumber_(defaultNumber) {}
// Searches in the phone book for a name. If the name is found it returns
// the corresponding number. If the name is not found it returns defaultNumber_
int read(string name){
map<string, int>::iterator it = data_.find(name);
if (it==data_.end()){
return defaultNumber_;
} else {
return it->second;
}
}
// Forwarding function to map operator []. It is not really necessary but it is added for clarity
int& write(string name){
return data_[name];
}
// Forward declaration of the "temporary object" returned by operator []
// See declaration below
class PhoneNumber;
PhoneNumber operator[](string name){
return PhoneNumber(this, name);
}
class PhoneNumber{
friend class PhoneBook;
private:
PhoneBook* const phoneBook_;
string name_;
// Constructors are private so that PhoneNumber can be used only by PhoneBook
// Default constructor should not be used
PhoneNumber() :
phoneBook_(NULL) {}
PhoneNumber(PhoneBook* phoneBook, string name) :
phoneBook_(phoneBook), name_(name) {}
public:
// conversion to int for read operations
operator int (){
return phoneBook_->read(name_);
}
// assignment operator for write operations
const int& operator = (const int& val){
return phoneBook_->write(name_) = val;
}
};
};
int main(){
PhoneBook phoneBook(999999);
phoneBook["Paul"] = 234657;
phoneBook["John"] = 340156;
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
cout << "To call John dial " << phoneBook["John"] << endl;
cout << "To call Frank dial " << phoneBook["Frank"] << endl;
return 0;
}
The class PhoneBook behaves like I would like and the program prints:
To call Paul dial 234657
To call John dial 340156
To call Frank dial 999999
I would like to ask you some questions:
Is there any better way to obtain a class behaving like the class I coded?
Has the technique I'm using a name so that I can search more info about it?
Do you see any drawback/possible improvement in my solution?
In the library I'm writing, enabling the behavior I obtained for PhoneBook::operator[]
in a similar situation is really important and I would really like to know what you think about my problem.
Thanks!
What you propose is the standard solution to this problem. It's usually
known as the proxy pattern or proxy idiom, and the helper class that you
return is called a proxy. (Since it is a nested class, simply calling
it Proxy is generally sufficient.)
I think you may implement two versions of operator [], one with const modifier and the other without. Then if you has a object say PhoneBook phoneBook(999999);, the if phoneBook is const object, only operator [] const can be called. If phoneBook is non-const object, default operator [] is called. If you want to call operator [] const given a non-const object, you may add a cast like static_cast<const PhoneBook&>(phoneBook)->operator[...].
#include <iostream>
#include <string>
#include <map>
using namespace std;
class PhoneBook{
private:
map<string, int> data_; // stores phone numbers
int defaultNumber_; // default number returned when no matching name is found
public:
PhoneBook(int defaultNumber) :
defaultNumber_(defaultNumber) {}
int operator [] (const string& name) const
{
map<string, int>::const_iterator it = data_.find(name);
if (it == data_.end())
{
return defaultNumber_;
}
else
{
return it->second;
}
}
int& operator [] (const string& name)
{
return data_[name];
}
};
int main(){
PhoneBook phoneBook(999999);
phoneBook["Paul"] = 234657;
phoneBook["John"] = 340156;
cout << "To call Paul dial " << phoneBook["Paul"] << endl;
cout << "To call John dial " << phoneBook["John"] << endl;
cout << "To call Frank dial " << static_cast<const PhoneBook&>(phoneBook)["Frank"] << endl;
return 0;
}