Unable to output vector with an ostream output C++ - c++

Hi there i was wondering if i could get some help with a problem i am having printing out the contents of a vector in C++
I am attempting to output all the variables of a class within one or two function calls in a particular order. However i am receiving an odd error when iterating through a vector
The error i am receiving is Error
error C2679: binary '=' : no operator found which takes a right-hand operand of type
'std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::basic_string<char,std::char_traits<char>,std::allocator<char>>>>>' (or there is no acceptable conversion)
My relevant code is below
ifndef idea
#define idea
using namespace std;
class Idea{
private:
int id;
string proposer, content;
vector<string> keywords;
public:
Idea(int i);
Idea(int i, string pro, string con);
void inputIdea();
int getID(){ return id; };
string getProposer(){ return proposer; };
string getContent(){ return content; };
vector<string> getKeyword();
bool wordSearch(string word);
friend ostream& operator<< (ostream& stream, const Idea& i);
void printIdea(ostream& os)const;
};
bool Idea::wordSearch(string word){
vector<string>::iterator it;
for(it = keywords.begin(); it < keywords.end(); it++){
if (word == *it){
return true;
}
}
if (content.find(word) != string::npos){
return true;
}
return false;
}
void Idea::printIdea(ostream& os)const{
vector<string>::iterator it;
os << "ID: " << id << endl;
os << "Proposer: " << proposer << endl;
os << "keywords: ";
for (it = keywords.begin(); it < keywords.end(); it++){ // error C2679
os << *it << " ,";
}
os << endl << "content: " << content << endl;
}
ostream& operator<<(ostream& os, const Idea& i)
{
i.printIdea(os);
return os;
}
i find it odd because the iterator function works in a different section of the code.
bool Idea::wordSearch(string word){
vector<string>::iterator it;
for(it = keywords.begin(); it < keywords.end(); it++){
if (word == *it){
return true;
}
}
if (content.find(word) != string::npos){
return true;
}
return false;
}
I wish to print out the id, then the proposer, then the keywords, then the content.

This is because printIdea is a const method. const methods aren't allowed to modify their members and thus keywords.begin() returns a vector<string>::const_iterator, not a normal one (vector<string>::iterator) . You should change the type of it :
vector<string>::iterator it;
to:
vector<string>::const_iterator it;
To have compatible types.
Or, if you have a compiler that has C++11 support you could just let the compiler figure it out for you:
auto it = keywords.begin()

printIdea is defined as
void Idea::printIdea(ostream& os)const
which means all non static members in that function are const qualified. Because of that keywords.begin() returns std::vector::const_iterator and not a std::vector::iterator. A std::vector::const_iterator is not assignable to a ``std::vector::iteratorwhich is howit` is declared so you get the error. You need to change
vector<string>::iterator it;
to
vector<string>::const_iterator it;
In order to get it to work.
Alternatively you can use a range based for loop and not even have to remember all of this like
for (auto& e : keywords)
{
os << e << " ,";
}

You need to use a const_iterator since your method printIdea() is const.
And you should use != to compare the iterator against end().

Related

Overloading << operator to print vector<MyClass>

I'm trying to overload the << operator to print a vector that contains elements of type Position (vector).
I managed to overload the << operator for type Position, but I can't figure out how to do it for vector. Can you help?
//position.h
#ifndef POSITION_H
#define POSITION_H
#include <iostream> // using IO functions
using namespace std;
class Position {
private:
int row;
int column;
public:
friend ostream& operator<<(ostream& os, const Position& P);
friend ostream& operator<<(ostream& os, const vector<Position>& VP);
};
#endif
//position.cpp
#include"Position.h"
#include <iostream> // using IO functions
#include<vector>
ostream& operator<<(ostream& os, const Position& P)
{
os << '(' << P.row << ',' << P.column << ')' << endl;
return os;
}
ostream& operator<<(ostream& os, const vector<Position>& VP)
{
Position placeholder;
for (int i = 0; i != VP.size(); i++)
{
placeholder = VP.at(i);
cout << placeholder << endl;
}
return os;
}
int main()
{
Position C1(2, 1);
Position C2(3, 1);
Position C3(4, 1);
vector<Position> cans;
cans.push_back(C1);
cans.push_back(C2);
cans.push_back(C3);
cout << cans;
system("pause");
}
I'm sure there's a duplicate on StackOverflow somewhere, but I cannot find it. I'm a bit surprised about this question, as I don't really see a critical issue at first sight. Did you get a compiler error or segmentation fault?
Every time you assign to Placeholder, you make a copy. This is not necessary at all: you can directly access the element at the index. As you limit the index to 0 to size(), you don't have to worry about going out-of-bounds, so don't use .at(i), which throws an exception if you go out of bounds. Just use VP[i].
Also not that std::endl flushes the buffer, which is slow. A normal enter/end-line can be achieved with the '\n' character.
Finally, using namespace std; is considered bad practice.
You have multiple options for processing the elements of the vector:
index-based for loop:
for (int i = 0; i != VP.size(); ++i) {
os << VP[i] << '\n';
}
Iterator-based for loop
for (auto it = cbegin(VP); it != cend(VP); ++it) {
os << *it << '\n';
}
range-based for loop
for (auto const& el : VP) {
os << el << '\n';
}
Algorithm for(each) loop
std::for_each(cbegin(VP), cend(VP),
[](auto const& el) { os << el << '\n'; });
Copy to ostream_iterator
std::copy(cbegin(VP), cend(VP),
std::ostream_iterator<Position>(os, "\n"));
Note that here you could also write <decltype(VP)::value> instead of <Position> to keep it generic, but that might be overkill in this situation.
And the last two have a C++20 ranges equivalent:
std::ranges::for_each(VP,
[](auto const& el) { os << el << '\n'; });
std::ranges::copy(VP,
std::ostream_iterator<Position>(os, "\n"));
Note:
friend ostream& operator<<(ostream& os, const vector<Position>& VP); doesn't have to be a friend of Position! It doesn't require access to the private members.

Overload =operator, can't get it to work

I am trying to overload the =operator on line 9 in the code below:
void searchContact(vector<Person> &people){
string searchTerm;
vector<Person>::iterator it;
cout << endl;
cout << "Enter search term: ";
getline(cin, searchTerm);
it = find(people.begin(), people.end(), searchTerm);
if (it != people.end()){
cout << "Element found in: " << *it << '\n';
}else{
cout << "Element not found\n";
}
}
My approach is this:
int data;
Person& operator=(Person& a) { return a; }
Person& operator=(int a) {
data = a;
return *this;
}
I am getting this error:
class.cpp:129:30: error: ‘Person& operator=(Person&)’ must be a nonstatic member function
Person& operator=(Person& a) { return a; }
^
class.cpp:130:26: error: ‘Person& operator=(int)’ must be a nonstatic member function
Person& operator=(int a) {
What is wrong with my approach, or am i doing it all wrong from the beginning?
First, you are overloading the wrong operator. std::find() uses operator== (comparison) instead of operator= (assignment). And, given that you are passing a std::string to std::find(), you need an operator== that takes a std::string as input, not a Person.
Second, you are trying to implement the operators as unary operators, which means they MUST be non-static members of your Person class. The compiler is complaining that they are not.
Third, if std::find() finds a match, you are passing *it to std::cout, so you need an overloaded operator<< that takes a Person for output.
Try something like this:
class Person
{
public:
...
bool operator==(const string &rhs) const
{
// compare members of *this to rhs as needed...
return ...; // true or false
}
/* alternatively:
friend bool operator==(const Person &lhs, const string &rhs)
{
// compare members of lhs to rhs as needed...
return ...; // true or false
}
*/
friend ostream& operator<<(ostream &out, const Person &p)
{
// output p to out as needed...
return out;
}
...
};
Then your search code will work:
void searchContact(vector<Person> &people)
{
cout << endl;
cout << "Enter search term: ";
string searchTerm;
getline(cin, searchTerm);
vector<Person>::iterator it = find(people.begin(), people.end(), searchTerm);
if (it != people.end()) {
cout << "Element found in: " << *it << '\n';
} else {
cout << "Element not found\n";
}
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Person{
private:
int data;
public:
Person(int data)
{
this->data = data;
}
int getData()
{
return data;
}
friend bool operator==( const Person &lhs, const int rhs);
};
bool operator== ( const Person &lhs, const int rhs )
{
return lhs.data == rhs;
}
void searchContact(std::vector<Person> &people){
int searchTerm = 1;
vector<Person>::iterator it;
it = find(people.begin(), people.end(), searchTerm);
if (it != people.end()){
cout << "Element found in: " << it->getData() << '\n';
}else{
cout << "Element not found\n";
}
}
int main(int argc, char **argv)
{
std::vector<Person> list1 = {1, 2, 3, 4};
std::vector<Person> list2 = {1, 2, 3, 5};
std::vector<Person> list3 = {1, 3, 7, 6, 9, 5, 2, 4};
searchContact(list1);
searchContact(list2);
searchContact(list3);
}
i don't know what do you want. please show your full code and tell what do you want.
if you want to find element in vector, you can write like this(not string. if ou want to find string, just change int to string and get data with cin or etc)

using iterator in ostream fails

I am attempting to implement a std::list to replace a linked list in this assignment. I am not allowed to change the declarations and can only change code in the .cpp file. For the most part I am making progress but I am having trouble implementing this
std::ostream& operator<< (std::ostream& out, const Section& section);
namely when I try to create an iterator it fails. I've used the iterator elsewhere in the code so I don't understand why it's failing here, I believe it's because it's private but I'm not sure how to resolve the issue without changing the .h file which was explicitly prohibited:
std::ostream& operator<< (std::ostream& out, const Section& section)
{
// 1. print the section header
out << setw(8) << left << section.getCourse()
<< setw(6) << left << section.getCallNumber();
out << ": " << section.getNumberOfStudents() << " students\n";
// 2. collect the students, sort, and print
Student* students = new Student[section.getNumberOfStudents()];
{
int i = 0;
for ( auto pos = section.students.begin();
pos != section.students.end(); pos++)
{
students[i] = pos;
++i;
}
}
sort (students, students+section.getNumberOfStudents());
for (int i = 0; i < section.getNumberOfStudents(); ++i)
out << " " << students[i] << "\n";
out << flush;
return out;
}
students[i] = pos;
should be changed to
students[i] = *pos;
because you want to copy the Student the iterator references, not the iterator itself.
But why a dynamic array of Student rather than a std::vector<Student>? Currently you have a memory leak because you don't delete[] students;
Edit 1
Removed.
Edit 2
Other than that, all I can see that it wrong is a missing std:: in front of
sort (students, students+section.getNumberOfStudents());
this is assuming there is no custom sort method being used.
Edit 3
Going off the rails here:
students[i] = *pos;
copies a Student from the list into the dynamic array students. This could be expensive, so here is an alternative:
First the bits and pieces needed to prove this out: Required includes
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>
a minimal Student class
class Student
{
std::string name;
public:
Student(std::string inname):name(inname)
{
}
const std::string & getname() const
{
return name;
}
friend bool operator<(const Student & a, const Student &b)
{
return a.name < b.name;
}
};
a minimal Section class
class Section
{
public:
std::list<Student> students;
};
a minimal outstream operator
std::ostream& operator<<(std::ostream& out, const Section& section)
{
A std::vector instead of an array, and a vector of constant references so we don't have to copy the students.
std::vector<std::reference_wrapper<const Student>> students;
Store references in the vector. Probably could do a one liner with std::copy and std::back_inserter, but this is getting a bit too much to absorb for one example.
for (const auto & student: section.students)
{
students.push_back(std::ref(student));
}
Sort the vector
std::sort(students.begin(), students.end());
print the vector
for (const auto & student: students)
{
out << student.get().getname() << " ";
}
return out;
}
and one main to rule them all and in the darkness bind them
int main()
{
Section s;
s.students.emplace_front("Tom");
s.students.emplace_front("Dick");
s.students.emplace_front("Harry");
std::cout << s;
}
And all in one easy to cut-n-paste block:
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>
class Student
{
public:
std::string name; // this is me being lazy. name should be private
Student(std::string inname):name(inname)
{
}
const std::string & getname() const
{
return name;
}
friend bool operator<(const Student & a, const Student &b)
{
return a.name < b.name;
}
};
class Section
{
public:
std::list<Student> students;
};
std::ostream& operator<<(std::ostream& out, const Section& section)
{
std::vector<std::reference_wrapper<const Student>> students;
// store references in the `vector`.
for (const auto & student: section.students)
{
students.push_back(std::ref(student));
}
// Sort the `vector`
std::sort(students.begin(), students.end());
// print the `vector`
for (const auto & student: students)
{
out << student.get().getname() << " ";
}
return out;
}
int main()
{
Section s;
s.students.emplace_front("Tom");
s.students.emplace_front("Dick");
s.students.emplace_front("Harry");
std::cout << s;
}
Or do what Remy suggested and use a std::vector<Student *> and a custom comparator to dereference the pointers for std::sort.
As others have stated, the error is because you are not dereferencing the iterator when populating your students[] array:
students[i] = pos; // <-- should be *pos instead!
I would suggest an alternative approach that should be faster and more efficient:
std::ostream& operator<< (std::ostream& out, const Section& section)
{
// 1. print the section header
out << setw(8) << left << section.getCourse()
<< setw(6) << left << section.getCallNumber();
out << ": " << section.getNumberOfStudents() << " students\n";
// 2. collect the students, sort, and print
std::vector<const Student*> students;
students.reserve(section.getNumberOfStudents());
for ( auto pos = section.students.cbegin();
pos != section.students.cend(); ++pos)
{
students.push_back(&(*pos));
}
sort (students.begin(), students.end(),
[](const Student *a, const Student *b) { return (*a < *b); }
);
for ( auto pos = students.cbegin();
pos != students.cend(); ++pos)
{
out << " " << *(*pos) << "\n";
}
out << flush;
return out;
}
I appreciate all your answers. Ended up being a much more basic issue. I had to implement the Section iterators to return student iterators.
Section::iterator Section::begin() {
return students.begin();
}
Section::const_iterator Section::begin() const {
return students.begin();
}
Section::iterator Section::end() {
return students.begin();
}
Section::const_iterator Section::end() const {
return students.begin();
}

Trouble with C++ maps and their content

This is rather extensive, so in advance, if you get through this, even without an answer or solution, thank you.
So, I have this program that is meant to be a basic social network, minus the user-interface, in which a user is represented by a Person object, which is responsible for maintaining a friend list, a block list, a list of messages, and a queue of pending friend requests. These lists are, respectively, of types std::map<std::string, Person>, std::map<std::string, Person>, std::vector<Message>, and std::queue<Message>, where the std::string for the two maps is a concatenation of the user's first and last names and the Message in the final two containers are and additional class I have defined. I have overloaded the << operator for Person such that it prints the user's first and last names, with a space in between. For some reason, when I go to print these names out, the return is empty, and I have no idea why. The following code is essentially a walkthrough what is happening.
The lines I am using to test my code in the main class:
std::string cFirst ("Chris");
std::string cLast ("Cringle");
SocialNetwork sn;
sn.addUser(cFirst,cLast);
The addUser() function in SocialNetwork:
void SocialNetwork::addUser(std::string first, std::string last){
std::string name = (first + last);
Person user (first, last);
_users.insert(std::pair<std::string, Person>(name, user));
}
Where _users is member data on the SocialNetwork of type std::map<std::string, Person>. The constructor for Person is:
Person::Person(std::string first, std::string last){
_first = first;
_last = last;
}
Where _first and _last are member data on Person that represent the user's first and last names. Then, back in the main class, after sn.addUser(cFirst,cLast);:
sn.printUsers();
Which looks like:
void SocialNetwork::printUsers(){
std::map<std::string, Person>::iterator it;
it = _users.begin();
while(it != _users.end()){
cout << it->first << endl;
cout << it->second << endl;
it++;
}
}
With the given code I have, the expected output for cout << it->first << endl; should be ChrisCringle, and it is. The expected output for cout << it->second << endl; should call the overloaded operator and should be Chris Cringle, but it simply prints a blank space. Any indications as to why would be greatly appreciated. Do I need to pass my params by reference? I have tried this already and seem to run into a lot of trouble. If something appears to be missing that may help, feel free to ask! Thanks again! I know I'll probably get a lot of flak for this long question but I do not think I can manage to make this any more of a simple question.
EDIT: The code for the overloaded operator is:
ostream& operator<<(ostream& os, const Person& per){
os << per._first << " " << per._last;
return os;
}
I just used all the code you've shown: http://ideone.com/mFBxTC
#include <string>
#include <iostream>
#include <map>
using namespace std;
struct Person {
Person(std::string first, std::string last);
std::string _first, _last;
};
ostream& operator<<(ostream& os, const Person& per){
os << per._first << " " << per._last;
return os;
}
struct SocialNetwork {
void addUser(std::string first, std::string last);
std::map<std::string, Person> _users;
void printUsers();
};
void SocialNetwork::addUser(std::string first, std::string last){
std::string name = (first + last);
Person user (first, last);
_users.insert(std::pair<std::string, Person>(name, user));
}
Person::Person(std::string first, std::string last){
_first = first;
_last = last;
}
void SocialNetwork::printUsers(){
std::map<std::string, Person>::iterator it;
it = _users.begin();
while(it != _users.end()){
cout << it->first << endl;
cout << it->second << endl;
it++;
}
}
int main() {
std::string cFirst ("Chris");
std::string cLast ("Cringle");
SocialNetwork sn;
sn.addUser(cFirst,cLast);
sn.printUsers();
return 0;
}
And it works fine. So error is elsewhere
Thats why one should post SSCCE when posting debugging questions.

STL Map - Displaying what is pointed to by find() function

For testing purposes, I'm running the following code through a for loop. Only the first three keys actually exist, and "Record found" is displayed as expected, along with the key, retrieved from findVertex->first.
My question is, how would I be able to access the second value being pointed to?
findVertex->secondseems obvious, but does not work, as the second value is an object I created, the declaration of which is given below the code, if it would be of any use.
for(int i = 0; i<10; i++)
{
map<int, vector<Vertex> >::const_iterator findVertex = vertexMap.find(i);
if(findVertex != vertexMap.end())
{
cout<<"\nRecord found: ";
cout<<findVertex->first;
cout<<findVertex->second; //does not work
}
else
cout<<"\nRecord not found";
}
Class code:
class Vertex
{
private:
int currentIndex;
double xPoint, yPoint, zPoint;
vector<double> attributes;
public:
friend istream& operator>>(istream&, Vertex &);
friend ostream& operator<<(ostream&, Vertex &);
};
Thanks
Your map is of the type
map<int, vector<Vertex>>
This means first is an int, and second is vector<Vertex>.
While you have defined operator<< for Vertex, there is no such function for vector<Vertex>. You'd have iterate through your vector, if you have access to C++11 you can use something like
if(findVertex != vertexMap.end())
{
cout << "\nRecord found: ";
cout << findVertex->first << '\n';
for (auto const& vertex : findVertex->second)
{
cout << vertex << '\n';
}
}
If you don't have access to C++11 you can do the same idea manually
if(findVertex != vertexMap.end())
{
cout << "\nRecord found: ";
cout << findVertex->first << '\n';
for (vector<Vertex>::const_iterator itVertex = findVertex->second.cbegin();
itVertex != findVertex->second.cend();
++itVertex)
{
Vertex const& vertex = *itVertex;
cout << vertex << '\n';
}
}
First of all you may not use const_iterator
map<int, vector<Vertex> >::const_iterator findVertex = vertexMap.find(i);
to display Vertex because you declared operator << with second parameter as a non-const reference
friend ostream& operator<<(ostream&, Vertex &);
^^^^^^^^
You should declare it like
friend ostream& operator<<(ostream&, const Vertex &);
^^^^^
Otherwise change the above statement to the following
map<int, vector<Vertex> >::iterator findVertex = vertexMap.find(i);
^^^^^^^^
And change this statement
cout<<findVertex->second; //does not work
to the following code snippet
for ( Vertex &v : findVertex->second ) cout << v << endl;
If you will modify the operator specyfying qualifier const for the second parameter then you can write
map<int, vector<Vertex> >::const_iterator findVertex = vertexMap.find(i);
^^^^^^^^^^^^^^
//...
for ( const Vertex &v : findVertex->second ) cout << v << endl;
^^^^^
Or instead of the range based for statement you can use an ordinary loop as for example
for ( std::vector<Vertex>::size_type i = 0; i < findVertex->second.size(); i++ )
{
std::cout << findVertex->second[i] << std::endl;
}
or
for ( std::vector<Vertex>::iterator it = findVertex->second.begin();
it != findVertex->second.end();
++it )
{
std::cout << *it << std::endl;
}