How to iterate a map of string and structure in C++? - c++

I am trying to iterate the below map and prints out everything in C++.
struct employee
{
uint16_t id;
uint8_t lastModifiedDate[8];
std::string value;
};
std::map<std::string, employee> m1;
As you can see the above map is of type key string and value as employee...
Below is try I have given but somehow whenever I compile the above code, I get bunch of exceptions at my console.. I am not sure which error will make sense to copy paste it here... So that's why I am not pasting it here for now.. If somebody needs it, I can make it small and then copy it here..
std:map<std::string, employee>::const_iterator itMap = m1.begin();
for (;itMap !=m1.end(); ++itMap) {
std::cout << itMap->first << " : " << itMap->second << std::endl;
}
std::cout << std::endl;
Any idea what wrong I am doing here?
Update:-
This is the error message I am seeing -
error: no match for operator<< in std::operator<<
>((* & std::operator<< , std::allocator >((* & std::cout), (* &
itMap.std::_Rb_tree_const_iterator<_Tp>::operator->, employee> >()->std::pair, employee>::first))), ((const char*)" : ")) <<
itMap.std::_Rb_tree_const_iterator<_Tp>::operator->, employee> >()->std::pair, employee>::second

std::cout won't know how to print your employee until you override operator<< for employee type. Like this:
std::ostream& operator<<(std::ostream& os, const employee& e)
{
os << e.id << lastModifiedDate[0] << value;
rteurn os;
}

You need to specify which member of the employee that you want to output to cout
std:map<std::string, employee>::const_iterator itMap = m1.begin();
for (;itMap !=m1.end(); ++itMap) {
std::cout << itMap->first << " : " << itMap->second.value << std::endl;
// ^^^^^^
}
std::cout << std::endl;

Related

Cannot iterate through map in print() method

I've done some exercises before where I loop through maps no problem. Now that I'm doing so in a class, I'm getting strange errors that I don't understand at all. It seems to happen at the instantiation of the iterator in the print() method.
error: conversion from ‘std::mapstd::__cxx11::basic_string<char,
bool>::const_iterator’ {aka
‘std::_Rb_tree_const_iterator<std::pair<const
std::__cxx11::basic_string, bool> >’} to non-scalar type
‘std::mapstd::__cxx11::basic_string<char, bool>::iterator’ {aka
‘std::_Rb_tree_iterator<std::pair<const
std::__cxx11::basic_string, bool> >’} requested 33 | for
(map<string, bool>::iterator i = jobs.begin(); i != jobs.end(); i++) {
Here is my code:
class Employee {
private:
string name;
map<string, bool> jobs;
public:
Employee() {
name = "";
jobs[""] = false;
}
Employee(const Employee &other) {
cout << "Copied." << endl;
name = other.name;
jobs = other.jobs;
}
Employee(string name, string task, bool trained) {
this->name = name;
jobs[task] = trained;
}
void setTask(string task, bool trained) {
jobs[task] = trained;
}
void print() const {
for (map<string, bool>::iterator i = jobs.begin(); i != jobs.end(); i++) {
pair<string, bool> jobs = *i;
cout << name << " is trained on " << jobs.first << "? " << jobs.second << endl;
}
}
};
I promise I did my best to look for solutions online before coming here. Sorry if I'm misunderstanding something extremely elementary.
I've tried making the print method const or not const, and I've experimented with using const_iterator and .cbegin()/.cend() in case it was being picky about that. Sadly, I'm just not very good at debugging yet.
void print() const
That const in the end means that this class method is a const class method. It can be called on const instances of this class. What it means is that, as far as this method is concerned, all members of its class are const.
map<string, bool>::iterator i = jobs.begin();
Since this is const, the begin() overload returns a const_iterator, instead of iterator, and that's the reason for your compilation error.
I've tried making the print method const or not const,
But what you haven't tried to do is use the current C++ standard, you are apparently using a very, very outdated textbook to learn C++. Current C++ makes all of this much easier:
void print() const {
for (auto &job:jobs)
cout << name << " is trained on " << job.first << "? " << job.second << endl;
}
And that's not even the best way to do it. I'll leave it to you to get your textbook updated, and learn about structured bindings that makes this even cleaner to read.
Your print member function is declared as const, so all occurrences/uses of data members of the class made within it will also be treated as const.
Thus, the calls to jobs.begin() and jobs.end() will invoke the const overloads of those functions, which have return types of const_iterator. So, to fix your issue, make i a const_iterator:
void print() const {
for (map<string, bool>::const_iterator i = jobs.begin(); i != jobs.end(); i++) {
pair<string, bool> localjob = *i; // Avoid "shadowing" member variable!
cout << name << " is trained on " << localjob.first << "? " << localjob.second << endl;
}
}
The member function print is a constant member function. It means that within the function data members of the class are constants. So instead of map<string, bool>::iterator you need to use map<string, bool>::const_iterator
Also it is a bad idea to redeclare the name jobs within the for loop. And moreover this declaration is redundant.
You should write
void print() const {
for (map<string, bool>::const_iterator i = jobs.cbegin(); i != jobs.cend(); i++) {
cout << name << " is trained on " << i->first << "? " << i->second << endl;
}
}
If your compiler supports C++ 17 then you could use range-based for loop the following way
void print() const {
for ( const auto &[first, second] : jobs ) {
cout << name << " is trained on " << first << "? " << second << endl;
}
}

how to print the content of a c++ function argument given such information

I have a c++11 code which has a function like the following:
bool prepareSwitch(const std::list<hardware_interface::ControllerInfo>& start_list,
const std::list<hardware_interface::ControllerInfo>& stop_list)
for debugging this code, I'd like to investigate/print for example the start_list, however, having a quite basic experience in c++ has made this confusing for me. Yet, the additional information that I can have about this input argument is about <hardware_interface::ControllerInfo> the described in this documentation.
I'm not sure how to use this information to print or investigate this input. Can someone guide a little about it?
using std::cout << start_list << std::endl; gave a compilation error.
To ease debugging you can overload the following operators. (adapt the formatting as needed)
std::ostream & operator<<(std::ostream & os, const hardware_interface::InterfaceResources &ir)
{
os << "hi: " << ir.hardware_interface << std::endl;
for (const auto & r : ir.resources)
{
os << "r: "<< r << std:;endl;
}
return os
}
std::ostream & operator<<(std::ostream & os, const hardware_interface::ControllerInfo &ci)
{
os << "name:" << ci.name << std::endl;
os << "type: " << ci.type<< std::endl;
for (const auto & cr : ci.claimed_resources)
{
os << "cr: " << cr << std::endl;
}
return os
}
Then you can print your functions arguments:
for (const auto& ci: startList)
{
std::cout << ci;
}

Why doesn`t operator<< work successfully?

While compiling the below code, I am getting an error:
Expression.h
class Expression{
...
protected:
std::ostream Os;
};
Expression.c
Expression::Expression() : Os(std::cout)
{
...
}
Expression::Expression(std::ofstream &os) : Os(os)
{
...
}
Expression::Dump()
{
Os << "=============================================================" << std::endl;
Os << "Os: " << Os << std::endl;
}
error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'std::ostream {aka std::basic_ostream<char>}')
What is my mistake? What should I do to fix it?
And while giving initial value to parameter like this Os(std::cout), what does it mean?
Consider
Os << "Os: " << Os << std::endl;
Let us unpack it into its full functional glory:
std::ostream& t1 = Os.operator <<("Os: ");
std::ostream& t2 = t1.operator <<(Os); // << Here
std::ostream& t3 = t2.operator <<(std::endl);
The problem is the line marked "Here". You are streaming an ostream to itself. This is nonsensical. What are you trying to do?
If you are trying to output an identifier for the stream, you should use the address:
Os << "Os: " << &Os << std::endl;
If you are trying to output the contents of the stream to stdout, you need to make Os be an ostringstream, and then output the string buffer:
std::ostringstream Os;
...
std::stdout << "Os: " << Os.str() << std::endl;
Note for the pedantic: I believe my breakdown of the original line into function calls and initializations is actually identical in this particular case (because there are no temporary objects - only references); in general, the lifetime of temporaries might be subtly different.
The error is because there is no standard operator<< that writes an ostream to another ostream.
Also, ostream can't be copy-constructed from another ostream, so if you are trying to specify an output ostream for Expression to write to then your Os member needs to be declared as a reference instead.
class Expression {
...
protected:
std::ostream &Os;
};
Expression::Expression() : Os(std::cout)
{
...
}
Expression::Expression(std::ofstream &os) : Os(os)
{
...
}
Expression::Dump()
{
Os << "=============================================================" << std::endl;
Os << "Os: " << SomethingThatIsNotOs << std::endl;
}

How to print a map

I am trying to print a map in an organized way. My map is defined like this:
map<std::string,std::vector<message *> > data;
where message is a struct like this:
struct message{
static unsigned int last_id;
unsigned int id;
std::string msg;
std::string timestamp;
message(const std::string& recvbuf_msg,const std::string& a_timestamp) :
msg(recvbuf_msg), timestamp(a_timestamp), id(++last_id)
{
}
};
I tried this way of printing it:
std::cout << (data[username]).at(0)->msg << std::endl;
But it gives a debug error when reaching that function, how can i solve it?
Error R6010 - abort() has been called suggests that either there is no entry for key username in the map, or the vector of messages for that user is empty. You need to make sure the containers are nonempty before accessing elements. It is a good idea to use iterators, here is an example of how to print the messages for all usernames:
for(auto mapIt = data.cbegin(); mapIt != data.cend(); ++mapIt)
{
std::cout << "printing data for " << mapIt->first << ":" << std::endl;
for(auto vectIter = mapIt->second.cbegin(); vectIter != mapIt->second.cend(); ++vectIter)
{
std::cout << (*vectIter)->msg << ", " << (*vectIter)->timestamp << ", "
<< (*vectIter)->id << std::endl;
}
}
The code uses auto, so if you are not using a C++11 compliant compiler, you will have to write the iterator types yourself.

print time on each call to std::cout

How would someone do that?
for example I do like:
std::cout << "something";
then it should print the time before "something"
Make your own stream for that :) This should work:
class TimedStream {
public:
template<typename T>
TimedStream& operator<<(const T& t) {
std::cout << getSomeFormattedTimeAsString() << t << std::endl;
return *this;
}
};
TimedStream timed_cout;
void func() {
timed_cout << "123";
}
You'd be able to use this class for every type for which std::cout << obj can be done, so no further work is needed.
But please note that the time will be written before every <<, so you cannot chain them easily. Another solution with explicit timestamp is:
class TimestampDummy {} timestamp;
ostream& operator<<(ostream& o, TimestampDummy& t) {
o << yourFancyFormattedTimestamp();
}
void func() {
cout << timestamp << "123 " << 456 << endl;
}
You could use a simple function that prints the timestamp and then returns the stream for further printing:
std::ostream& tcout() {
// Todo: get a timestamp in the desired format
return std::cout << timestamp << ": ";
}
You would then call this function instead of using std::cout directly, whenever you want a timestamp inserted:
tcout() << "Hello" << std::endl;
ostream& printTimeWithString(ostream& out, const string& value)
{
out << currentTime() << ' ' << value << std::endl;
return out;
}
Generate current time using your favourite Boost.DateTime output format.
This looks like homework. You want something in the line of:
std::cout << time << "something";
Find a way the retrieve the time on your system, using a system call.
Then you'll have to implement a << operator for your system-dependent time class/struct.