I want to add class object in STL map as a value in C++.It's like std::map<CString,class myClass*>myMap. But compilers showing me error in doing this. Should I have to implement all comparison operators overloading for that class?? If not then how do I can achieve that?
Code is as follows:
// header file
#pragma once
#include "afxsock.h"
#include"NetworkDataProcessor.h"
#include"MainFrm.h"
#include"ChattingDialog.h"
#include<map>
using namespace std;
class CConnectionManager :public CAsyncSocket
{
public:
static CConnectionManager *GetClientInstance();
BOOL ClientSignIn(CString, CString);
void ConnectToServer();
public:
CString m_sendBuffer;
int m_nBytesSent;
int m_nBytesBufferSize = MAX_BUFFER_SIZE;
virtual void OnClose(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual void OnSend(int nErrorCode);
public:
std::map<CString, CChattingDialog* >ChatWindows;
private:`enter code here`
CConnectionManager();
~CConnectionManager();
static CConnectionManager * client_instance;
};
// cpp file function:
void CMyMessangerView::OnClientListClick(NMHDR* pnmh, LRESULT* pResult)
{
DWORD dwPos = ::GetMessagePos();
CPoint point((int)LOWORD(dwPos), (int)HIWORD(dwPos));
GetListCtrl().ScreenToClient(&point); int nIndex; if ((nIndex = GetListCtrl().HitTest(point)) != -1)
{
CString string = GetListCtrl().GetItemText(nIndex, 0);
CChattingDialog chatingDlg;
chatingDlg.SendToUser = string;
CString user = chatingDlg.UserRealName(string);
CConnectionManager *client = CConnectionManager::GetClientInstance();
client->ChatWindows.insert(pair<CString, CChattingDialog *>(user, &chatingDlg));
UpdateData(FALSE);
chatingDlg.DoModal();
}
*pResult = 0;
}
ERRORS:
15 IntelliSense: no instance of overloaded function "std::map<_Kty, _Ty, _Pr, _Alloc>::insert [with _Kty=CString, _Ty=CChattingDialog *, _Pr=std::less, _Alloc=std::allocator>]" matches the argument list
argument types are: (std::pair)
object type is: std::map, std::allocator>
Error 3 error C2976: 'std::map' : too few template arguments c:\projects\poc\mymessanger\mymessanger\clientconnection.h 25 1 MyMessanger
Error 4 error C2665: 'std::pair::pair' : none of the 3 overloads could convert all the argument types c:\projects\poc\mymessanger\mymessanger\mymessangerview.cpp 131 1 MyMessanger
16 IntelliSense: no instance of constructor "std::pair<_Ty1, _Ty2>::pair [with _Ty1=CString, _Ty2=CChattingDialog &]" matches the argument list
argument types are: (CString, CChattingDialog *) c:\Projects\POC\MyMessanger\MyMessanger\MyMessangerView.cpp 131 29 MyMessanger
etc... few more errors like indicating the same
Thanks everyone for responding to this problem. Thank you Fomin Arseniy.
The solution to this problem is what I guessed in the question and Fomin Arseniy said above.
We must have to overload at least Copy constructor and assigning operator for class we are going to use in map as a value.
First ,map declaration for user defined data types needs to be like
std::map<CString, class CChattingDialog> ChatWindows;
instead of
std::map<CString, CChattingDialog> ChatWindows;
and second,I added two functions
CChattingDialog& operator=(const CChattingDialog &s);
CChattingDialog(const CChattingDialog &s);
in the class CChattingDialog . Used inserting method as advised by Fomin Arseniy.
client->ChatWindows[user] = &chatingDlg;
compiled the code successfully.
We must have to provide public constructor, copy constructor, desctructor, assining operator and operator< (less than) if need to add user defined data types in STL map.
You use std::map in wrong way. You should rewrite your code as follows:
client->ChatWindows[user] = &chatingDlg;
(If you want to use map::insert method you can read about it here: http://www.cplusplus.com/reference/map/map/insert/. There is no pair inserting as you do, there is one method that returns pair of interator/succes).
However, you also asked what do you need to implement in your class to store it in map not by pointer but by value as:
std::map<CString, CChattingDialog> ChatWindows;
Correct answer is: you need public constructor, copy constructor, desctructor, assining operator and operator< (less than) in class CChattingDialog but not in class CConnectionManager.
Map uses them to have possibility to correctly store, copy, delete and sort elements of this class in it.
Related
I am a beginner of C++, and I code what The Cherno teaches in his 100th video of the C++ series, showing at 16:50. But VS is always giving me error.
If without commenting the const part, VS gives me error c3848. After adding const, VS give me error c2676.
I have checked the way to use std::hash on cppreference, and searched for the error on Google, but get nothing. It's just "a little bit" too hard for a beginner like me.
Below is the code.
#include<iostream>
#include<map>
#include<unordered_map>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
};
namespace std {
template<>
struct hash<CityRecord>
{
size_t operator()(const CityRecord& key) //const noexcept
{
return hash<std::string>()(key.Name);
}
};
}
int main()
{
std::unordered_map<CityRecord, uint32_t> foundedMap;
foundedMap[CityRecord{ "London", 500000, 2.4, 9.4 }] = 1850;
uint32_t NewYorkYear = foundedMap[CityRecord{ "NY", 7000000, 2.4, 9.4 }];
}
As a beginner, I just want to know how to use the hash function in this case.
There is a much easier solution, without opening the std namespace and specializing the std::hash
If you look at the definition of the std::unordered_map in the CPP reference here, then you will read:
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator< std::pair<const Key, T> >
> class unordered_map;
It is clear and normal, to hand in template parameters for the key-type and the value-type value. However, if the key-type if a custom type, like in your case, then you need to add additional functionality.
First, you need to add hash functionionality. If you read here about std::hash, then the only function the will be called is the "function call operator".
And this must be a "const" function, which will fix one of your problems.
And of course, you may add this function to your struct. That is completely OK. Please see in the example code below. With taht, you can give your own class as a template parameter for the hash functionality to the std::unordered_map. Cool.
If we look at the next template parameter of the std::unordered_map, then we will find std::equal_to. And if we read about this in cppreference, then we will find the following statement:
Function object for performing comparisons. Unless specialised, invokes operator== on type T.
So, we need to add a comparison operator == to your custom struct to satisfy requirements.
Please note: It is a good approach to encapsulate the methods operating on the data of classes within the class and not define them as free functions. Because only the methods of the class should work on the data of the class. If you would later change something in a class and have a free function doing work on the class members. So, please try to follow that approach.
Then, next, the comparison. So, we define the "operator ==" in your class and then have to compare element by element.
For easing up this task, there is a library function called std::tie. Please see here. This basically creates a std::tuple from the given parameters with the advantage, that all comparison functions are already defined and can be immediately reused.
By following the above described approach, the whole implementation will be much simpler.
Please see the below example code:
#include<iostream>
#include<map>
#include<unordered_map>
#include<tuple>
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
// For std::equal_to
bool operator == (const CityRecord& cr) const { return std::tie(Name, Population, Latitude, Longtitude) == std::tie(cr.Name, cr.Population, cr.Latitude, cr.Longtitude); }
// For hashing
size_t operator()(const CityRecord& key) const { return std::hash<std::string>{}(key.Name); }
};
int main() {
// Definition of the unordered_map
std::unordered_map<CityRecord, uint32_t, CityRecord> foundedMap;
// Adding data
foundedMap[CityRecord{ "London", 500000, 2.4, 9.4 }] = 1850;
uint32_t NewYorkYear = foundedMap[CityRecord{ "NY", 7000000, 2.4, 9.4 }];
}
You need to make the overloaded operator() for the specialization of hash for CityRecord a const member function as shown below. Additionally, we also need to overload operator== for CityRecord as shown below:
struct CityRecord
{
std::string Name;
uint64_t Population;
double Latitude, Longtitude;
//friend declaration for operator== not needed since we've a struct
};
//implement operator==
bool operator==(const CityRecord &lhs, const CityRecord &rhs)
{
return (lhs.Name == rhs.Name) && (lhs.Population == rhs.Population) && (lhs.Latitude ==rhs.Latitude) && (lhs.Longtitude == rhs.Longtitude);
}
namespace std {
template<>
struct hash<CityRecord>
{
//-----------------------------------------------vvvvv-->added this const
size_t operator()(const CityRecord& key) const
{
return hash<std::string>()(key.Name) ^ hash<uint64_t>()(key.Population) ^ hash<double>()(key.Latitude) ^ hash<double>()(key.Longtitude);
}
};
}
Working demo
Here we use an (unnamed) hash<string> object to generate a hash
code for Name, an object of type hash<uint64_t> to generate a hash from Population, and an object of type hash to generate a hash from Latitute and finally an object of type hash<double> to generate a hash from Longitute. Next, we exclusive OR these results to form an overall hash code for the given CityRecord object.
Note that we defined our hash function to hash all the four data members so that our hash function will be compatible with our definition of operator== for CityRecord.
For an assignment (this is a fairly small part I've been stuck on, I'm not asking for anyone to do the homework), we were supplied with the following code and its call in the main file:
template <class number_type>
class Point {
public:
Point(const number_type& x_, const number_type& y_) : x(x_),y(y_) {}
// REPRESENTATION
number_type x;
number_type y;
};
template <class number_type, class label_type>
class QuadTree {
public:
QuadTree(const number_type& number_, const label_type& label_) : number(number_), label(label_){}
number_type number;
label_type label;
};
int main() {
std::vector< std::pair<Point<int>,char> > simple_points;
QuadTree<int,char> simple;
}
However, using a very similar style to the supplied coding produces a "no matching function" error in my terminal:
I'm confused as to why it doesnt work in this case, as well as what I can do to fix it.
As a note, we are not allowed to use c++11, structs, and a few other tools. Also, we are not permitted to change anything in the "main" function, so QuadTree simple; MUST stay as-is
main.cpp: In function ‘void simple_test()’:
main.cpp:110:22: error: no matching function for call to ‘QuadTree<int, char>::QuadTree()’
QuadTree<int,char> simple;
^
main.cpp:110:22: note: candidates are:
In file included from main.cpp:14:0:
quad_tree.h:56:5: note: QuadTree<number_type, label_type>::QuadTree(const number_type&, const label_type&) [with number_type = int; label_type = char]
QuadTree(const number_type& number_, const label_type& label_) : number(number_), label(label_){}
^
quad_tree.h:56:5: note: candidate expects 2 arguments, 0 provided
quad_tree.h:54:7: note: QuadTree<int, char>::QuadTree(const QuadTree<int, char>&)
class QuadTree {
^
quad_tree.h:54:7: note: candidate expects 1 argument, 0 provided
This code:
QuadTree<int,char> simple;
is attempting to call the default constructor. However, since you provide a constructor, the default constructor is implicitly deleted. The constructor you provided is:
QuadTree(const number_type& number_, const label_type& label_)
So you'd have to do:
QuadTree<int, char> simple(42, 'C');
Your QuadTree constructor takes 2 parameters, but you probably (based on your error message) have a definition like
QuadTree<int,char> simple;
which declares an object with no parameters passed to the constructor. You need to do something like
QuadTree<int, char> simple(2, 'a'); // need to specify the parameters
Note that because you defined a constructor, the compiler does not generate a default one for you anymore.
I am making a Queue for running functions. I put the functions that require being called into a std::deque<bool(*)()> Then I later on cycle through the deque calling each function and letting it run, sometimes even doing things based on the return.
The problem I am having is actually with regards to placing these functions inside of the deque.
I have this deque inside a class called A2_Game. I also have a class called Button.
My code resembles the following:
class Button
{
bool DoInput();
}
class A2_Game
{
std::deque<bool(*)()> Input_Functions;
bool EnterName()
}
A2_Game::OtherMethod()
{
Button* btn1 = new Button();
Input_Functions.push_back(&A2_Game::EnterName); //The compiler told me to do this and it still won't compile the line..
Input_Functions.push_back(btn1->DoInput);
//Loop
}
I cannot determine how to fix my compile errors. I suspect some of you may be able to just tell me outright what needs to be changed/done in order to get this to compile, by looking at what I've shown here. In case that is !true then here are the compile errors.
error C2664: 'std::deque<_Ty>::push_back' : cannot convert parameter 1 from 'bool (__thiscall A2_Game::* )(void)' to 'bool (__cdecl *const &)(void)'
error C3867: 'Button::Doinput': function call missing argument list; use '&Button::Doinput' to create a pointer to member
if you want to push back functions you can use std::function (or boost if your compiler doesn't support c++11)
std::deque<std::function<bool()> > function_list;
Button* btn1 = new Button();
function_list.push_back([this](){return EnterName();});
function_list.push_back([btn1](){return btn1->DoInput();});
make sure everything in the lambda is still going to be valid when you call it from the function_list.
EDIT:
boost equivalent
std::deque<boost::function<bool()> > function_list;
Button* btn1 = new Button();
function_list.push_back(boost::bind(&A2_Game::EnterName,this));
function_list.push_back(boost::bind(&Button::DoInput,btn1));
The problem is that the signature of the class methods don't match with the function signature bool (*)(). The signatures of the two methods are bool (Button::*)(); or bool (A2_Game::*)(); respectively. (The actual class to which the method belongs is part of its signature!)
The solution here is to use functors/function objects. Functors are wrapper objects around "callable elements" that are useful if you want to treat functions like objects (in a OOP sense). If you have boost at hand your code could look similar to this (code compiles):
#include <boost/function.hpp>
#include <deque>
class Button
{
public:
bool DoInput() { return true; }
};
class A2_Game
{
public:
typedef boost::function<bool()> Functor;
std::deque<Functor> Input_Functions;
bool EnterName() { return true; }
void OtherMethod();
};
void A2_Game::OtherMethod()
{
Button* btn1 = new Button();
Input_Functions.push_back(boost::bind(&A2_Game::EnterName, this));
Input_Functions.push_back(boost::bind(&Button::DoInput, btn1));
}
boost::bind combines a function pointer with the reference to an actual class instance and returns an function object of the same type as A2_Game::Functor.
Note that boost::function has been integrated into the C++11 standard (see here), so if your project supports C++11 simply use #include <functional> and std instead of boost namespaces.
I've been set an assignment to create an rpn calculator that takes infix notation as input. So part of it is that it has to print out different stages of the process. So first it should separate a string into tokens and then store in a vector. Then it should convert this to rpn notation (e.g 3+4 -> 3 4 +) which is the part im stuck on now the part I'm stuck on now.
I've been recommended to use virtual abstract functions for this. So first I create a class with the abstract function. Then I create a subclass which converts a string to tokens stored in a string vector, this part works fine. Then I should create another subclass which converts the input string to rpn notation, therefore I have to call the function to convert to tokens at the start of this sub-class, this is the bit which I think is going wrong.
I have been given some code as a template and so far it's been very buggy so there might be something wrong with the syntax where the error is.
So I have this as my main class
template<typename T>
class tokenstream {
public:
virtual bool process(const std::string& input, std::vector<T>& output) = 0;
};
Then this as the first subclass
class tokenifier: public tokenstream<std::string> {
public:
bool process(const std::string& input, std::vector<std::string>& output) {
//this part works fine, ive tested it.
};
So then I have to create another subclass and then call the above function inside it, this is the part where it goes wrong.
class infix2rpn: public tokenstream<std::string> {
private:
tokenifier *tokens;
public:
tokenifier(tokenstream *_tokens): tokens(_tokens) {} //I think this line is the problem
bool process(const std::string& input, std::vector<std::string>& output) {
//call the underlying tokenstream object
std::vector<std::string> infixtokens;
if(!tokens->process(input, infixtokens))
{
return false;
}
return shunting_yard(infixtokens, output);
}
bool shunting_yard(const std::vector<std::string>& input, std::vector<std::string>& output){
//i've tested the shunting_yard algorithm and it works fine
}
};
When I try to compile it I get the error "ISO C++ forbids declaration of 'tokenifier' with no type [-fpermissive].
So the part I don't understand is how to call other virtual functions from another subclass.
Thanks
Your class is called infix2rpn, so its constructor should be named infix2rpn as well, not tokenifier. This has nothing to do with virtual functions.
Moreover, your attribute should be a tokenstream<std::string>*, not a tokenifier*, because you can't convert the tokenstream<std::string>* you get in the constructor to a tokenifier*.
tokenifier(tokenstream *_tokens): tokens(_tokens) {}
This was probably meant to be constructor, but in that case, the name of the method should be infix2rpn, same as the class name.
The error means, that you specified method tokenifier that has not specified return type, only constructors and destructors have no return type.
Note that void also specification of return type, in that case it means nothing returned.
I am trying to iron out my first compile in a long time, and I think this is the last hurdle.
I am trying to create this type of hierarchy in my design.
class chin_
{
private:
charon_* engine;
public:
chin_();
chin_(charon_ &handle)
{
engine = handle;
}
~chin_();
};
//////////////
class charon_ {
private:
chin_ engine_input;
public:
charon_(){
engine_input = chin_(this);
}
~charon_();
};
I am getting errors that tell me there is no matching function for call to
'chio::chin_::chin()'
it also says, mind you this is only when I change the constructor to charon_&
public:
chin_(const charon_ &handle)
{
engine = handle;
}
sys/../headers/chio.h:104:5: note: no known conversion for argument 1 from ‘charon::charon_* const’ to ‘const charon::charon_&’
When I use the * instead of & I get this instead, which is by far more baffling.
sys/../headers/chio.h:104:5: note: chio::chin_::chin_(const charon::charon_*)
sys/../headers/chio.h:104:5: note: candidate expects 1 argument, 0 provided
I've tried this and that, and I figure it is probably something super simple. I've tried to match my code up squarely with the examples I've found though so I don't know what else I should be trying, I'd like to be able to figure this sort of stuff out on my own. I just am not having any luck with it.
EDIT:
I update the code but I left the updated error for the bottom.
sys/chin.cpp:19:14: error: cannot convert ‘charon::charon_’ to ‘charon::charon_*’ in assignment
It takes me to this code
chin_::chin_(charon_ &handle) {
engine = handle;
}
engine is defined as
charon_* engine; and handle appears to be an address and should fall right into place, but it isn't. I think I am not using this correctly.
When you declare something like this :
chin_ engine_input;
chin_ needs a constructor with no parameters or you have to pass the parameters to it in the initializer list, otherwise you will get the error about no matching constructor.
What you can do is either have a default constructor that takes no params. Or make engine_input a pointer and create it with :
engine_input = new chin_(handle);
Alternatively you can pass handle to chin_ in the initializer list like this :
foo::foo(charon* handle):
chin_(handle)
{
}