So I have a map that has user defined keys and the values in it are sets of objects too. So I'm trying to write some print function but I have no idea how to do that. (I'm kind of new to maps and sets).
My problem function:
void print() const
{
for (auto& itr : my_mmap)
{
std::cout << "Key for this set:" << itr.first << "\n\n";
for (int i = 0; i< itr.second.size(); i++)
{
std::cout << itr.second[i] << std::endl;
}
}
}
Here's my class:
#include <iostream>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <set>
class Enclosing {
private:
class Key {
int m_number;
std::string m_name;
public:
Key(int num, std::string name) :m_number(num), m_name(std::move(name)) {};
bool operator<(const Key& rhs) const {
return std::tie(m_number, m_name) < std::tie(rhs.m_number, rhs.m_name);
}
friend std::ostream& operator<<(std::ostream& os, const Key& k) {
return os << '{' << k.m_number << ',' << k.m_name << '}';
}
};
class Nested {
std::string m_str;
double m_dbl;
bool m_boolean;
public:
Nested(std::string str, double dbl, bool boolean) :m_str(std::move(str)), m_dbl(dbl), m_boolean(boolean) {};
friend std::ostream& operator<<(std::ostream& os, const Nested& n) {
return os << '{' << n.m_str << ',' << n.m_dbl << ',' << n.m_boolean << '}';
}
};
std::multimap<Key, std::set<Nested>> my_mmap;
public:
template <class... Args>
void add_new_object_to_mmap(Args&&... args) {
my_mmap.emplace(std::piecewise_construct, std::forward<Args>(args)...);
}
/*
THAT PROBLEM FUNCTION
*/
void print() const
{
for (auto& itr : my_mmap)
{
std::cout << "Key for this set:" << itr.first << "\n\n";
for (int i = 0; i< itr.second.size(); i++)
{
std::cout << itr.second[i] << std::endl;
}
}
}
static Enclosing& get_singleton() {
static Enclosing instance;
return instance;
}
};
}
So the problem is that I am getting an error "no operator "[]" match these operands". How can I output my map and set in the best way?
The problem is that we cannot use indexing on a std::set. Thus itr.second[i] is not valid because itr.second is an std::set.
To solve this you can use a range-based for loop as shown below:
for (const auto&elem:itr.second)
{
std::cout << elem << std::endl;
}
Related
In the following programm std::cout << ex.what() << std::endl; does not print anything.
What's the problem with this code?
#include <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <cstring>
class Interval_OutOfRange : public std::out_of_range {
public:
std::stringstream ss;
Interval_OutOfRange(int min, int max, int value)
: std::out_of_range{"interval value out of range"}
{
ss << value << " is not inside intervall [" << min << ", " << max << "]";
}
char const * what() const noexcept override {
return ss.str().c_str();
}
};
template<int Min, int Max>
class Interval {
public:
Interval(int value) : value_{value} {
throw Interval_OutOfRange{Min, Max, value};
}
auto get() const { return value_; }
auto set(int value) { value_ = value; }
private:
int value_;
};
int main() {
try {
Interval<7, 17> obj(19);
}
catch (Interval_OutOfRange& ex) {
std::cout << ex.what() << std::endl;
}
}
My issue is my last increment_watch function. I would like to be able modify parts of the Movie class while it is in a vector container. Right now I am only able to grab a specific Movie object and its increment but I am unable to change or modify any of it while it is in a vector. I would like to be able to modify or add +1 to the watched element. Is this at all possible?
EDIT: I have updated the "increment_watched" function taking suggestions from the comments. I have tried to pass by reference the watched variable but the "mov.set_watched" call in the increment_watched function is not taking effect.
#include <iostream>
#include <vector>
#include <string>
class Movie {
friend std::ostream &operator<<(std::ostream &os, const Movie &p);
private:
std::string name;
std::string ratting;
int watched;
public:
Movie() = default;
Movie(std::string name, std::string ratting, int watched)
: name{name}, ratting{ratting}, watched{watched} {}
void increment_watched(std::vector<Movie> vec, std::string name);
bool operator<(const Movie &rhs) const { // always overload
return this->watched < rhs.watched;
}
bool operator==(const Movie &rhs) const {
return (this->name == rhs.name && this->watched == rhs.watched); // always overload
}
void set_name(std::string name) {
this->name = name;
}
std::string getName() {
return name;
}
void set_ratting(std::string ratting) {
this->ratting = ratting;
}
std::string getRatting() {
return ratting;
}
void set_watched(int watched) {
this->watched = watched;
}
int getWatched() {
return watched;
}
};
std::ostream &operator<<(std::ostream &os, const Movie &p) {
os << p.name << " : " << p.ratting << " : " << p.watched;
return os;
}
// template function to display any vector
template <typename T>
void display(const std::vector<T> &lem) {
std::cout << "[ ";
for (const auto &elem: lem)
std::cout << elem << " ";
std::cout << " ]"<< std::endl;
}
// I want to modify this function to increment the "watched" variable by one
void increment_watched(std::vector<Movie> vec, std::string name, int &watched){
watched =+ 1;
for (auto &mov: vec){
if (mov.getName() == name){
std::cout << name << std::endl;
mov.set_watched(watched);
}
}
}
int main() {
std::vector<Movie> vec;
int watched = 1;
Movie p1 {"Star Wars", "PG", 2};
Movie p2 {"Indiana Jones", "PG", 1};
Movie p3 {"Matrix", "PG-13", 5};
vec.push_back(p2);
vec.push_back(p3);
std::cout << p1.getName() << std::endl;
std::cout << p1.getRatting() << std::endl;
p1.set_watched(100);
vec.push_back(p1);
std::cout << p1.getWatched() << std::endl;
display(vec);
increment_watched(vec, "Star Wars", watched);
display(vec);
return 0;
}
Thank you user WhozCraig, this lead me to answering my question!
You response lead the to the correct output. I wanted to change the values and completely over looked passing the vec variable to pass by reference. I knew it was something small that I was over looking
To all those who posted helpful comments to help post better questions on the site, thank you. I am new to StackOverflow. I will review the provided helpful links in order to post better questions in the future. Some commented that I posted the same question twice, I panicked and deleted the post because it was locked, I didnt know what to do so I thought I would start over.
Here is the corrected code:
#include <iostream>
#include <vector>
#include <string>
class Movie {
friend std::ostream &operator<<(std::ostream &os, const Movie &p);
private:
std::string name;
std::string ratting;
int watched;
public:
Movie() = default;
Movie(std::string name, std::string ratting, int watched)
: name{name}, ratting{ratting}, watched{watched} {}
void increment_watched(std::vector<Movie> vec, std::string name);
bool operator<(const Movie &rhs) const { // always overload
return this->watched < rhs.watched;
}
bool operator==(const Movie &rhs) const {
return (this->name == rhs.name && this->watched == rhs.watched); // always overload
}
void set_name(std::string name) {
this->name = name;
}
std::string getName() {
return name;
}
void set_ratting(std::string ratting) {
this->ratting = ratting;
}
std::string getRatting() {
return ratting;
}
void set_watched(int watched) {
this->watched = watched;
}
int getWatched() {
return watched;
}
};
std::ostream &operator<<(std::ostream &os, const Movie &p) {
os << p.name << " : " << p.ratting << " : " << p.watched;
return os;
}
// template function to display any vector
template <typename T>
void display(const std::vector<T> &lem) {
std::cout << "[ ";
for (const auto &elem: lem)
std::cout << elem << " ";
std::cout << " ]"<< std::endl;
}
// I want to modify this function to increment the "watched" variable by one
void increment_watched(std::vector<Movie> &vec, std::string name, int &watched){
for (auto &mov: vec){
if (mov.getName() == name){
std::cout << name << std::endl;
mov.set_watched(watched + 1);
}
}
}
int main() {
std::vector<Movie> vec;
int watched = 3;
Movie p1 {"Star Wars", "PG", 2};
Movie p2 {"Indiana Jones", "PG", 1};
Movie p3 {"Matrix", "PG-13", 5};
vec.push_back(p2);
vec.push_back(p3);
std::cout << p1.getName() << std::endl;
std::cout << p1.getRatting() << std::endl;
p1.set_watched(100);
vec.push_back(p1);
std::cout << p1.getWatched() << std::endl;
display(vec);
increment_watched(vec, "Star Wars", watched);
display(vec);
return 0;
}
I want to sort a vector according to the custom datatype. I followed Sorting a vector of custom objects
answer. I am using lambda function to compare the objects. However I am getting compiler errors as following while sorting:
/usr/include/c++/7/bits/stl_algo.h:1852: error: cannot bind non-const lvalue reference of type 'MyData&' to an rvalue of type 'std::remove_reference::type {aka MyData}'
*__first = _GLIBCXX_MOVE(__val);
^
main.cpp
#include "mydata.h"
#include <vector>
int main()
{
std::vector<MyData> tv {MyData(2,21), MyData(3,20), MyData(10,100), MyData(9,20)};
std::sort(tv.begin(), tv.end(), []( MyData const& lhs, MyData const& rhs ){
return lhs.get_size() < rhs.get_size();
});
return 0;
}
mydata.cpp
#ifndef MYDATA_H
#define MYDATA_H
#include <iostream>
#include <algorithm>
class MyData
{
private:
int *m_data;
int m_x;
size_t m_size;
public:
MyData(const size_t &size,int const &x):
m_data(new int[size]),
m_x(x),
m_size(size)
{
std::fill_n(m_data,m_size, m_x);
std::cout << *m_data << " ctor" << m_size << std::endl;
}
MyData(const MyData& other):
m_data(new int[other.m_size]),
m_x(other.m_x),
m_size(other.m_size)
{
std::fill_n(m_data,m_size, m_x);
std::cout << *m_data << " cctor" << m_size << std::endl;
}
MyData& operator=(MyData& other)
{
std::cout << *m_data << " cbctor" << m_size << std::endl;
swap(*this,other);
std::cout << *m_data << " cactor" << m_size << std::endl;
return *this;
}
~MyData(){
std::cout << *m_data << " dtor" << m_size << std::endl;
delete[] m_data;
}
size_t get_size() const{
return m_size;
}
friend void swap(MyData& first, MyData& second){ // (1)
std::swap(first.m_size, second.m_size);
std::swap(first.m_x, second.m_x);
std::swap(first.m_data, second.m_data);
}
friend std::ostream& operator<< (std::ostream& stream, const MyData& mydata) {
stream << *(mydata.m_data) << " " << mydata.m_size << " "<< mydata.m_x;
return stream;
}
};
#endif // MYDATA_H
I do not understand the error. I am not changing the value of the reference, why I am getting this error.
I also read this but did not understand why it is occurring here.
Thank you.
There can be some type of declarations copy assignment operator.
It is typical declaration of a copy assignment operator when copy-and-swap idiom can be used:
MyData& operator=(MyData other);
It is typical declaration of a copy assignment operator when
copy-and-swap idiom cannot be used (non-swappable type or degraded
performance):
MyData& operator=(const MyData& other);
So to use swap in your realization you can declare copy assignment operator as MyData& operator=(MyData other);
You should modify your code like this :
#include <iostream>
#include <fstream>
#include <thread>
#include <atomic>
#include <algorithm>
#include <vector>
using namespace std;
class MyData
{
private:
int *m_data;
int m_x;
size_t m_size;
public:
MyData(const size_t &size, int const &x) :
m_data(new int[size]),
m_x(x),
m_size(size)
{
std::fill_n(m_data, m_size, m_x);
std::cout << *m_data << " ctor" << m_size << std::endl;
}
MyData(const MyData& other) :
m_data(new int[other.m_size]),
m_x(other.m_x),
m_size(other.m_size)
{
std::fill_n(m_data, m_size, m_x);
std::cout << *m_data << " cctor" << m_size << std::endl;
}
MyData& operator=(const MyData& other)
{
std::cout << *m_data << " cbctor" << m_size << std::endl;
//swap(*this, other);
if (this != &other)
{
this->m_data = new int[other.m_size];
for (size_t i = 0; i < other.m_size; ++i)
{
this->m_data[i] = other.m_data[i];
}
this->m_x = other.m_x;
this->m_size = other.m_size;
}
std::cout << *m_data << " cactor" << m_size << std::endl;
return *this;
}
~MyData() {
std::cout << *m_data << " dtor" << m_size << std::endl;
delete[] m_data;
}
size_t get_size() const {
return m_size;
}
friend void swap(MyData& first, MyData& second) { // (1)
std::swap(first.m_size, second.m_size);
std::swap(first.m_x, second.m_x);
std::swap(first.m_data, second.m_data);
}
friend std::ostream& operator<< (std::ostream& stream, const MyData& mydata) {
stream << *(mydata.m_data) << " " << mydata.m_size << " " << mydata.m_x;
return stream;
}
};
int main()
{
std::vector<MyData> tv{ MyData(2,21), MyData(3,20), MyData(10,100), MyData(9,20) };
std::sort(tv.begin(), tv.end(), [](MyData const& lhs, MyData const& rhs) {
return lhs.get_size() < rhs.get_size();
});
std::system("pause");
return 0;
}
Using C++ 14, templates and a Bridge pattern, I'm trying to create a generic way of adding objects to a container named Shapes (vector of Shape objects). I would like to be able to automatically support new datatypes which are added to the container and print them without modifying the original implementation of the Shape class. Instead, I would like to only provide a new print(T) function, and everything should work out-of-the-box.
Below is my code, I still have some problems getting it to compile. Can anyone please help me out? Many thanks.
#include <iostream>
#include <memory>
#include <vector>
#include <map>
#include <string>
using namespace std;
void print(const int toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(const double toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(const vector<int> & toPrint) {
for (auto & it : toPrint) {
cout << " " << it;
}
cout << endl;
}
void print(const map<int, string> & toPrint) {
for (auto & it : toPrint) {
cout << " " << it.first << " : " << it.second << endl;
}
cout << endl;
}
class Shape {
public:
template<typename T>
Shape(T &&t) {
pimpl_ = make_unique<Specialization<T>>(t);
}
void print() const {
pimpl_->print();
}
private:
struct Base {
virtual void print() const = 0;
virtual ~Base() = default;
};
template<typename T>
struct Specialization: public Base {
Specialization(T &t) :
internalObject_ { std::move(t) } {
}
void print() const override {
::print(internalObject_);
}
T internalObject_;
};
unique_ptr<Base> pimpl_;
};
typedef vector<Shape> Shapes;
void print(Shapes const & shapes) {
for (auto & shape : shapes) {
shape.print();
}
}
int main() {
Shapes shapes;
shapes.push_back(1);
shapes.push_back(2.0);
shapes.push_back(0.3);
shapes.push_back(vector<int> { 10, 11, 12 });
shapes.push_back(map<int, string> { { 0, "elmo" }, { 1, "leom" } });
print(shapes);
return 0;
}
Here is a patched up version of your code which compiles (on clang). As pointed out in the comments there are several issues that need to be addressed (this code leaks memory for example), but this should get you back on track.
#include <iostream>
#include <vector>
using namespace std;
void print(int toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(double toPrint) {
cout << " " << toPrint;
cout << endl;
}
void print(vector<int> toPrint) {
for (auto & it : toPrint) {
cout << " " << it;
}
cout << endl;
}
class Shape {
public:
template<typename T>
Shape(T t) {
pimpl_ = new Specialization<T>(t);
}
void print() const{
pimpl_->print();
}
private:
struct Base {
virtual void print() const = 0;
};
template<typename T>
struct Specialization: public Base {
Specialization(T t) {
internalObject_ = new T(t);
}
void print() const{
::print(*internalObject_);
}
T* internalObject_;
};
Base * pimpl_;
};
typedef vector<Shape> Shapes;
void print(Shapes const & shapes) {
for (auto & shape : shapes) {
shape.print();
}
}
int main() {
Shapes shapes;
shapes.push_back(1);
shapes.push_back(2.0);
shapes.push_back(0.3);
shapes.push_back(vector<int> { 10, 11, 12 });
print(shapes);
return 0;
}
I am having an issue with my C++ program. Right now I am just trying to create a generic "variable" utilizing operator overloading. So the issues is when I determine
the type of data passed. (I must do this because I am later overloading the << operator so that ostream can output the correct data) The conditional statement
does not work as expected. Here is the code
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = 5;
std::cout << var << std::endl;
return 0;
}
That should be the final code once that class is done. But the error persists when I try to set var = blah. It gives cannot convert const char* to int or
cannot convert char to int or anything of the sort. It was my impression that that code does not matter at all if it is not true. If I comment out the part
where I set the correct variables it runs with no issue
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; //in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; //str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; //fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; //fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; //ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl;
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
return 0;
}
This runs, but only when I comment var = blah as shown above. So how can I fix this? Again it was my understanding that if the if statement is not true
the code inside wont even run. But it seem to anyway. I do not understand why this is happening. Can someone shed some light on it? Basically all I want to
do is create a "generic data type" and use the operator=() to set it.
I understand the need is to be able to declare:
SLVar var;
and later decide to assign integer, string, float, whatever without the need of fixing the type by a template (kind of dynamic typing)
I'm proposing a solution with a lot of compromises, without typeinfo at all and without templates (the template is useless here since you have to perform a type check within the function)
either, I kept only const char * and int types for simplicity's sake but that can be easily extended.
When assigning, the type is set in an enumerate, later used by the console write function.
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
class SLVar
{
private:
const char* str;
int in;
enum TheType { TYPE_INT, TYPE_CHARPTR, TYPE_UNKNOWN };
TheType type;
public:
SLVar() : type(TYPE_UNKNOWN)
{}
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
SLVar & operator=(int var)
{
in = var;
type=TYPE_INT;
return *this;
}
SLVar &operator=(const char *var)
{
str = var;
type=TYPE_CHARPTR;
return *this;
}
};
std::ostream& operator<<(std::ostream& os, const SLVar& var)
{
switch (var.type)
{
case SLVar::TYPE_CHARPTR:
return os << var.str;
case SLVar::TYPE_INT:
return os << var.in;
default:
return os; // not printing anything
}
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
var = 35; // kind of dynamic typing through assignment
SLVar var2;
var2 = 56;
std::cout << var << " " << var2 << std::endl;
}
result:
Hello world
35 56
It's still missing a lot of things, like default constructor, copy constructor... but the principle works.
Try something along the lines of:
#include <iostream>
#include <vector>
#include <istream>
#include <ostream>
template <typename T>
class SLVar {
public:
SLVar<T>() {} ; // Defualt constructor
SLVar<T>(T value) :
var(value)
{} ;
T var ;
T getvalue() {return var ;}
// This lets you use the class as though it was the object
inline operator T() {return var;}
T operator=(T newvar)
{
var = newvar ;
}
};
int main()
{
SLVar<double> var_dbl(3.14);
SLVar<int> var_int(5) ;
SLVar<const char*> var_str("hello") ;
SLVar<char> var_char('y') ;
// And now to test...
std::cout << "Dbl: " << var_dbl << std::endl;
std::cout << "Int: " << var_int << std::endl;
std::cout << "Str: " << var_str << std::endl;
std::cout << "Char: " << var_char << std::endl;
// Lets try resetting the values
var_dbl = 4.6 ;
var_int = 7 ;
var_str = "goodbye" ;
var_char = 'n' ;
std::cout << "Dbl: " << var_dbl << std::endl;
std::cout << "Int: " << var_int << std::endl;
std::cout << "Str: " << var_str << std::endl;
std::cout << "Char: " << var_char << std::endl;
// Lets try some math on the double variable
std::cout << "Dbl * 0.5: " << var_dbl*0.5 << " (this shoudl be 2.3)" << std::endl;
return 0;
}
The downside is that (I'm I'm sure you've realized) the streamer wont work if you try to do SLVar<std::string>. There you just need to use SLVar<const char*>. I've also added the line:
inline operator T() {return var;}
So that the the class can act as an object of the type it is suppose to represent. So you can use the SLVar<double> as a double in a formula, for example.