Link List - no operator '<<' matches - c++

My c++ is really poor. Anyhow with the code snippet bellow why do I get a error on the << in the do while loop when outside of it I get no error. The error is: no operator "<<" matches these operands. However the string w picks up the word fine. I read somewhere I may have to overload it but why? And how would I over load it for a link list.
Thanks in advance.
void print()
{
HashTable *marker = headOne;
HashTable *inList;
for( int i = 0; i < tableSize; i++ )
{
cout << i << ": " << marker->number << endl;
if(marker->child != NULL)
{
inList = marker;
do
{
string w = inList->word;
cout << w << endl;
inList = inList->child;
}
while(inList != NULL);
}
marker = marker->next;
}//end for loop
}

In order to be able to cout a std::string you have to include:
#include <string>
#include <iostream>

This works:
// Missing includes and using
#include <string>
#include <iostream>
using namespace std;
// missing struct
struct HashTable {
HashTable* next;
HashTable* child;
string word;
int number;
};
// missing vars
HashTable ht;
HashTable* headOne = &ht;
int tableSize = 5;
// Unchanged
void print()
{
HashTable *marker = headOne;
HashTable *inList;
for( int i = 0; i < tableSize; i++ )
{
cout << i << ": " << marker -> number << endl;
if(marker->child != NULL)
{
inList = marker;
do
{
string w = inList -> word;
cout << w << endl;
inList = inList -> child;
}
while(inList != NULL);
}
marker = marker -> next;
}//end for loop
}

I read somewhere I may have to overload it but why?
Because there's no overload that matches your need.
And how would I over load it for a link list.
You can do this outside of your class or struct:
(where T is the type of the object that you want to print)
std::ostream& operator<<(std::ostream& os, const T& obj)
{
/* write obj to stream */
return os;
}
This is just an example that prints a vector:
std::ostream& operator<<(std::ostream& os, vector<int>& obj)
{
for (auto &i : obj)
os << i << " ";
return os;
}
Then I would be able to simply do this cout << n.vec; where n is the class object and vec the name of a vector of ints.

Related

Vector of Objects - C++. No operator "<<" matches these operands, Error

I am a beginner in programming.I have a problem. I am trying to code the Enigma machine. I have two classes. One for Enigma, one for rotors. Rotors are small parts of the enigma machine, that doesn't matter for the problem. My problem is the error. I cannot cout, the function cout << rotors[0].GetRotor(); which should return my vector of integers. I have no idea why is that. I don't need that to my program, but I'm not sure if my adding rotor to enigma void AddRotor(Rotor rotor) { rotors.push_back(rotor); }function, called in "TakeRotors" function, works right. In my opinion, it should work well, but I can't check it. Debugger, unfortunately, doesn't show any values of vector<Rotor> rotors; permutation so I am not sure :( Any help would be great. Thank You.
Here's my full, needed code :)
#include <iostream>
#include <vector>
using namespace std;
class Rotor {
public:
vector <int> permutation;
int position;
Rotor(vector<int> permutation) {
position = 0;
permutation;
}
vector<int> GetRotor() const {
return permutation;
}
};
class Enigma {
public:
vector<Rotor> rotors;
void AddRotor(Rotor rotor) {
rotors.push_back(rotor);
}
void PrintRotor(const vector<Rotor>& rotors) {
cout << rotors[0].GetRotor(); // Error right here
cout << rotors[0].position;
}
void setupRotor(int index) {
Rotor rotor = rotors[index];
}
void MoveRotor(int index) {
rotors[index].position++;
cout << "Before" << endl;
// cout << rotors[index].permutation.data << ' ';
Enigma::PrintRotor(rotors);
rotate(rotors[index].permutation.begin(), rotors[index].permutation.begin() + rotors[index].permutation.size(), rotors[index].permutation.end());
cout << "After" << endl;
Enigma::PrintRotor(rotors);
}
};
vector<int> take_numbers(int number) {
vector<int> numbers;
for (int i = 0; i < number; i++) {
int number;
cin >> number;
numbers.push_back(number);
}
return numbers;
}
void take_rotors(int number_letters, Enigma* enigma) {
int numberOfRotors;
// int numberOfNotch, positionOfNotch;
cout << "Give number of Rotors" << endl;
cin >> numberOfRotors;
for (int i=0; i < numberOfRotors; i++) {
vector<int> permutation = take_numbers(number_letters);
Rotor Rotor(permutation);
enigma->AddRotor(Rotor); // I am not sure if it adds Rotors fine.
}
}
int main()
{
Enigma enigma;
int number_letters, move_rotor;
cout << "Give number of letters in alphabet" << endl;
cin >> number_letters;
take_rotors(number_letters, &enigma);
// take_reflectors(number_letters, &enigma);
cout << "Which rotor do you want to move (index)" << endl;
cin >> move_rotor;
enigma.MoveRotor(move_rotor);
return 0;
}
There is no operator<<(std::ostream&,const std::vector<int>&) if you want it you need to supply your own. However, overloading operators for types you don't own is not recommended, so I would rather write a function:
void print_vector(std::ostream& out, const std::vector<int>& vect) {
for (int i : vect) {
out << i << '\n';
}
}
That you can call like this
print_vector(std::cout, rotors[0].GetRotor());
Alternatively you can supply an overload for << that prints all the Rotor:
std::ostream& operator<<(std::ostream&,const Rotor& rotor) {
out << rotor.position;
for (auto& i : rotor.GetRotor()) {
out << i;
}
// modify and add more to your likings
return out;
}
Once you have that you can also provide an overload to print a vector of rotors that you can use in Enigma::PrintRotor (which currently only prints the first element of the vector):
std::ostream& operator<<(std::ostream& out,const std::vector<Rotor>& rotors) {
for (const auto& r : rotors) {
out << r << '\n';
}
return out;
}
PS your naming is a little confusing. A Rotor has a GetRotor which returns permutations !?! I strongly suggest to use better names. If I have Rotor r; then r is the Rotor and it is not obvious what a GetRotor will do. Maybe rename it to GetPermutations?

How to add integers and strings in the same vector?

I need help for my university homework. i'm still new to this.
Basically i am doing a run-length encoding and i don't know how to add the letter after the counter:
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
void error(std::string str)
{
throw std::runtime_error(str);
}
int main()
{ int counter = 1;
std::string id;
std::vector<int> v;
std::cout << "Enter the data to be compressed: ";
std::cin >> id;
try
{ for(int i = 0; i < id.size(); i++)
{
if(std::isdigit(id[i]))
error("invalid input");
}
std::cout << "The compressed data is: ";
for(int i = 0; i < id.size(); i++)
{
if(id[i] == id[i+1])
{
counter++;
}
else if(id[i]!= id[i+1])
{
v.push_back(counter);
v.push_back(id[i]);
counter=1;
}
}
for(int j = 0; j < v.size(); j++)
std::cout << v[j];
}
catch(std::runtime_error& str)
{
std::cerr << "error: " << str.what() << std::endl;
return 1;
}
return 0;
}
For example if i input aaabbb, the probram should output 3a3b. The problem is that it outputs 397398 97 and 98 being the ascii code for a and b.
i don't know how to put the letter after the counter and for them to be in the same vector.
If you want to serialize as a string try this :
#include <iostream>
#include <string>
#include <vector>
#include <stdexcept>
#include <sstream>
void error(std::string str) {
throw std::runtime_error(str);
}
int main() {
std::ostringstream stream;
int counter = 1;
std::string id;
std::cout << "Enter the data to be compressed: ";
std::cin >> id;
try {
for (int i = 0; i < id.size(); i++) {
if (std::isdigit(id[i]))
error("invalid input");
}
std::cout << "The compressed data is: ";
for (int i = 0; i < id.size(); i++) {
if (id[i] == id[i + 1]) {
counter++;
} else if (id[i] != id[i + 1]) {
stream << counter;
stream << (char) id[i];
counter = 1;
}
}
std::cout << stream.str() << std::endl;
} catch (std::runtime_error& str) {
std::cerr << "error: " << str.what() << std::endl;
return 1;
}
}
v[j] from std::cout << v[j] is of type int and that is why std::cout writes a number. To write it as a character, you should cast v[j] to char as follows: std::cout << (char)v[j]. In this way, std::cout will use the char specialization, not the int one.
While the other answers might give you the output you need, I believe the idiomatic way to solve this is using a class to hold both the character and its count. There are two obvious choices.
std::pair
Could also be std::tuple if you prefer it for consistency or whatever reason. Save your results in a std::vector<std::pair<char, int>. This saves the information, but to print it you would need to define an appropriate function. Add elements via
v.emplace_back(character, count);
Wrapper Class
If you want to offer some functionality without outside helper classes, define a custom wrapper class such as the following.
class CharacterCount {
private:
char character;
int count;
public:
CharacterCount(char character, int count):
character(character), count(count) {}
explicit operator std::string() const { return std::to_string(count) + character;
// Other helper functions or constructors you require
}
This simplifies printing
for (auto& character_count : v)
std::cout << static_cast<std::string>(character_count);
I believe because std::ostream::operator<< is templated, you cannot get an implicit conversion to std::string to work. I would advise against implicit conversion anyway.
You can use the same emplace_back syntax as before because we offer an appropriate constructor.
So you take your input in a string and ultimately just need to stream this information out, ultimately meaning there's really no reason to store the information in a vector, just output it! You can use find_if with a lambda to find the non-consecutive character (or find_if_not if you prefer.)
for(string::const_iterator finish, start = cbegin(id); start != cend(id); start = finish) {
finish = find_if(start, cend(id), [value = *start](const auto i) { return i != value; } );
cout << distance(start, finish) << *start;
}
Live Example

How do you initialize template class members that uses other template classes?

I'm having trouble correctly setting up and accessing my member functions of a class. This node class is being used to build a Max Heap Tree. However, when the tree is being initialized, I'm getting garbage data and not what I am initializing it to.
#ifndef HEAPNODE_H_INCLUDED
#define HEAPNODE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include <array>
using namespace std;
template <class Type> class HeapNode {
private:
int key;
Type value;
public:
HeapNode(int key, Type const &value) {
this->key = key;
this->value = value;
}
// Returns the key of the node
int getKey() {
return key;
}
// Returns the value of the node
Type getValue() {
return value;
}
// Displays the node
void displayNode() {
cout << "Key: " << key << "\tValue: " << value << endl;
}
};
#endif
Here is the class that builds my Heap Tree. I've tried setting the initializations in the constructor every which way, and I'm still getting junk data. In addition, I set the constructor to take an integer, but when I'm creating a tree in my driver program, it won't let me put an argument for it which initiates an array of that size.
#ifndef MAXHEAPTREE_H_tINCLUDED
#define MAXHEAPTREE_H_INCLUDED
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <string>
#include "HeapNode.h"
using namespace std;
template <class Type> class MaxHeapTree {
private:
HeapNode<Type> *array;
HeapNode<Type> *root;
int elementSize;
int height;
int leafCounter;
public:
// Constructor
MaxHeapTree(int n = 10) : elementSize(0), height(0), leafCounter(0) {
this->elementSize = elementSize;
this->height = height;
this->leafCounter = leafCounter;
HeapNode<Type> *array = new HeapNode<Type>[n];
}
// Destructor
~MaxHeapTree();
void arrayDisplay() {
cout << "Original array size: " << sizeof(array)/4 << endl;
}
// Returns the number of elements in the tree
int getSize() {
return elementSize;
}
// Returns the height of the tree
int getHeight() {
return height;
}
// Returns the number of leaves in the tree
int leaves() {
return leafCounter;
}
int countLines(const string fileName) {
string line;
int lineCount = 0;
ifstream myFile (fileName.c_str());
if (myFile.is_open()) {
while (getline(myFile, line)) {
lineCount++;
}
}
else {
cout << "Error opening file" << endl;
}
myFile.close();
return lineCount;
}
// Reads structure from a text file and builds a max heap
void buildTree(const string fileName) {
string line;
string key;
string value;
int lines = countLines(fileName);
int i = 0;
cout << "Lines: " << lines << endl;
HeapNode<Type> *newArray[lines];
cout << "Size of newArray: " << sizeof(newArray)/4 << endl;
ifstream myFile (fileName.c_str());
if (myFile.is_open()) {
while (getline(myFile, line)) {
key = line.substr(0, 1);
int x = atoi(key.c_str());
value = line.substr(1);
HeapNode<Type> *hNode = new HeapNode<Type>(x, value);
newArray[i] = hNode;
cout << "newArray[" << i << "] = ";
newArray[i]->displayNode();
i++;
}
}
else {
cout << "2 - Error opening file." << endl;
}
myFile.close();
}
};
#endif
How do you initialize template class members that uses other template classes?
In the same way you initialize members of non templates that don't use other templates.
when the tree is being initialized, I'm getting garbage data and not what I am initializing it to.
I was using MaxHeap<string> *heapTree1;
Well, there's your problem. Apparently you never created an instance of MaxHeap<string>.

A vector holds class objects, The class object contains 3 strings per object. How do i find the specific string, then delete the entire element?

I have a class that contains 3 elements for example {first_name, Last_name, Phone}
I have a vector that holds this set of information. In what manner could I go about looking for a single element of the set, for example find(last_name), and delete all elements that contain that specific last name?
I've tried many examples and have searched far and wide throughout the world wide google. Please help. Attached is bits of code:
int number = 4;
vector <Friend> BlackBook(number);
Friend a("John", "Nash", "4155555555");
Friend d("Homer", "Simpson", "2064375555");
BlackBook[0] = a;
BlackBook[1] = d;
Now that's just same basic code for the set up. Here's a couple of things i've tried. But the more I look at what the code says, the more it seems as if it's not allowing for a string argument... but then i don't know how to give a class arguement with respect to a specific string... well I don't know what i'm doing wrong. I have a feeling I could do this with pointers, but the whole pointer thing isn't clicking yet. But heres some things i've tried.
vector <Friend> :: iterator frienddlt;
frienddlt = find (BlackBook.begin(), BlackBook.end(), nofriend);
if (frienddlt != BlackBook.end())
{
BlackBook.erase( std::remove( BlackBook.begin(), BlackBook.end(), nofriend), BlackBook.end() );
}
else
{
cout << nofriend <<" was not found\n" << "Please Reenter Last Name:\t\t";
}
When I compile the project the header file stl_algo.h opens and points to line 1133.
Any Help would be much appreciated!! thank you!
Try remove_if
My example:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
struct Friend {
string first_name;
string last_name;
string phone;
};
bool RemoveByName (vector<Friend>& black_book, const string& name) {
vector<Friend>::iterator removed_it = remove_if(
black_book.begin(), black_book.end(),
[&name](const Friend& f){return f.first_name == name;});
if (removed_it == black_book.end())
return false;
black_book.erase(removed_it, black_book.end());
return true;
}
int main() {
vector <Friend> black_book {
Friend {"John", "Nash", "4155555555"},
Friend {"Homer", "Simpson", "2064375555"}
};
if (RemoveByName(black_book, "John")) {
cout << "removed" << endl;
} else {
cout << "not found" << endl;
}
if (RemoveByName(black_book, "Tom")) {
cout << "removed" << endl;
} else {
cout << "not found" << endl;
}
for (int i = 0; i < black_book.size(); ++i) {
Friend& f = black_book.at(i);
cout << f.first_name << " " << f.last_name << " " << f.phone << endl;
}
return 0;
}
Output:
removed
not found
Homer Simpson 2064375555
Of course, you can always loop over all Friend elements and delete them manually.
Blackbook::iterator friend = Blackbook.begin();
while (friend != Blackbook.end())
{
if (friend->last_name == bad_name)
{
friend = Blackbook.erase(friend);
}
else
{
++friend;
}
}

std::getline "blends" strings together

I am attempting to read data from a .txt file and put its contents into a linked list that holds two strings per node. Because some of the strings in the .txt file contain spaces, and I'd rather leave them as is than kill the spaces, I am using std::getline().
I have the .txt file formatted as so:
"Tourism, Recreation & Sports Management"
“TRS”
"Anthropology"
“ANT”
And so on but without the blank lines between each line. The linked list has a print() method that prints the data in this format : data1 / data2 ; data1 / data2:
So, when I print a node with data1 == "Tourism, Recreation & Sports Management" and data2 == "TRS" the desired output is:
"Tourism, Recreation & Sports Management" / "TRS";
HOWEVER, what I actually get is:
"TRS"ism, Recreation & Sports Management"
However, when I read the lines and assign them to strings, and then print out those strings without inserting them into the linked list, I get correct output. That is
std::cout << data1 << std::endl;
std::cout << data2 << std::endl;
Will correctly output:
"Tourism, Recreation & Sports Management"
"TRS"
What gives?
Edit:
Linked List header:
#ifndef _2DLL_H_
#define _2DLL_H_
#include <iostream>
#include <string>
class Llist{
struct node{
//node member var
std::string department;
std::string abv;
node * next;
//node member methods
std::string search(std::string dep);
void print();
void remove(const std::string dep);
void clear();
//constructer
node(const std::string dep , const std::string a):department(dep), abv(a), next(NULL){}
};// end node
public:
//Llist member var
node * head;
//LList constructer & destructor
Llist():head(NULL){}
~Llist(){clear();}
//Llist member functions
std::string search(const std::string dep);
void insert(const std::string dep , const std::string a);
void print();
void remove(const std::string dep);
void clear();
const int operator[](unsigned int index)const;
};// end Llist
#endif //_2DLL_H_
Linked List .cpp
#include "2DLL.h"
#include <algorithm>
//=========INSERT==============
void Llist::insert(const std::string dep, const std::string a){ //will just prepend. Fuck the police;
node * n = new node(dep , a);
n->next = head;
head = n;
}
//========PRINT=================
void Llist::print(){
if(head==NULL){
std::cout << "ERROR: List is empty" << std::endl;
}
else{
head->print();
}
}
void Llist::node::print(){
if(next==NULL){
std::cout << department << ";" << abv << std::endl;
}
else{
std::cout << department << ";" << abv << " / " ;
std::cout << std::endl;
next->print();
}
}
//=======REMOVE========
void Llist::remove(const std::string dep){
if(head==NULL){
std::cout << "ERROR: List is empty" << std::endl;
}
else{
head->remove(dep);
}
}
void Llist::node::remove(const std::string dep){
if(next->department == dep){
node * n = next;
next = n->next;
delete n;
}
else{
next->remove(dep);
}
}
//===========CLEAR()==================
void Llist::clear(){
if(head==NULL){
std::cout << "ERROR:List is empty" << std::endl;
}
else{
head->clear();
head = NULL;
}
}
void Llist::node::clear(){
if( this==NULL){
return;
}
else{
next->clear();
delete this;
}
}
//=========OPERATOR=============
/*
const int Llist:: operator[] (unsigned int index) const{
node * n = head;
for(int i = 0 ; i < index && n!=NULL ; ++i){
n=n->next;
}
return n->data;
}
*/
//========SEARCH====================
std::string Llist::search(std::string dep){
if(head == NULL){
std::cout << "ERROR: List is empty" << std::endl;
return "ERROR";
}
else{
//dep.erase(std::remove(dep.begin(),dep.end(),' '),dep.end());
//std::cout << dep << std::endl;
return head->search(dep);
}
}
std::string Llist::node::search(std::string dep){
if(department == dep){
return abv;
}
else{
return next->search(dep);
}
}
Implementation of the Reading
#include "genCollege.cpp"
#include "genDepartment.cpp"
#include "2DLL.cpp"
#include <ctime>
#include <fstream>
using namespace std;
int main(){
std:: ifstream file;
file.open("DepList.txt");
std::string department;
std::string abv;
srand(time(0));
/*for (int i = 0 ; i < 30 ; i++){
std::string college = genCollege();
std::string department = genDepartment(college);
std::cout << "College: "<< college << std::endl;
std::cout << "\t" << "Department: " << department << std::endl;
std::cout << std::endl;
} */
Llist list;
while(file.is_open()){
if(file.eof()){break;};
std::getline(file , department);
std::getline(file, abv);
list.insert(department , abv);
}
//file.close();
list.print();
return 0 ;
}
As the user n.m suggested, it seemed that because I was reading a text file for Windows and running program on Ubuntu, the output looked wrong. His answer word for word:
"You have a text file created for Windows that has \r\n as the line terminator. Your program either runs on a un*x or fails to open the file in text mode. Thus you are getting \r at the end of each string, which messes your terminal window. "
He suggested I check to see if the the last character in the string after I've used std::getline() is \r and, if it is, to remove it from the string. I did this by simply making a substring of the strings in question after I acquired them with std::getline()
I then inserted the new substrings into the linked list and the print() method now outputs as desired.