Erase–remove idiom c++ (without friend function) - c++

I have two classes:
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <cmath>
#include <list>
using namespace std;
enum class Programm{Koch, Normal, Bunt, Fein};
class KleidSt {
private:
string bezeichnung;
int gewicht;
Programm Pflegehinweis;
public:
KleidSt(string bezeichnung, int gewicht);
KleidSt(string bezeichnung, int gewicht, Programm Pflegehinweis);
int get_gewicht() const;
bool vertraeglich(Programm)const;
int get_Pflegehinweis() const;
friend ostream& operator<<(ostream& os, const KleidSt& kleid);
};
class WaschM{
private:
int ladungsgewicht;
vector<KleidSt> wasch;
public:
WaschM(int ladungsgewicht);
void zuladen(const vector<KleidSt>& z);
void waschen(Programm);
friend ostream& operator<<(ostream& os, const WaschM& kleid);
int programme() const;
vector<KleidSt> aussortieren(Programm pr);
};
I want to create the function vector<KleidSt> aussortieren(Programm), that will delete all elements from wasch vector, if these elements will have Pflegehinweis attribute higher(by using static_cast<int>(elem) function) then is defined by aussortieren function and will return a vector of deleted elements.
My first try was to use Erase–remove idiom:
vector<KleidSt> WaschM::aussortieren(Programm pr){
wasch.erase(remove_if(begin(wasch), end(wasch), vertraeglich(pr)), end(wasch));
return wasch;
}
And here vertraeglich(pr) does the job, that I described above.
But it's clearly returns error, because vertraeglich function was defined out of the scope of class WaschM. The question is: how can I use Erase–remove idiom(or maybe some other variants), such that code will work?

Looks like a job for a lambda function
vector<KleidSt> WaschM::aussortieren(Programm pr){
wasch.erase(
remove_if(
begin(wasch),
end(wasch),
[&](const KleidSt& k){ return k.vertraeglich(pr); }),
end(wasch));
return wasch;
}
Untested code.

You can use a lambda function.
vector<KleidSt> WaschM::aussortieren(Programm pr){
wasch.erase(remove_if(begin(wasch),
end(wasch),
[pr](KleidSt const& item) {return item.vertraeglich(pr);},
end(wasch));
return wasch;
}

Related

expected primary-expression before ‘.’ token

I am fairly new to classes. I created a class called Counter which basically creates a counter object and has certain data members and function members associated with it.
The header file for the class is:
#ifndef c
#define c
#include <iostream>
#include <string>
#include <vector>
using std::vector; using std::string; using std::ostream;
class Counter{
int v_;
public:
vector<string> log_;
int initialized_;
Counter(int);
int value();
int get_v() const { return v_; } //getter
void set_v(int val) { v_ = val; } //setter
friend ostream & operator<<(ostream &, Counter &);
friend Counter operator+(const Counter &, const Counter &);
};
ostream & operator<<(ostream &, Counter &);
Counter operator+(const Counter &, const Counter &);
#endif
and the cpp implementation file looks like this:
#include "counter.h"
#include <iostream>
#include <vector>
#include <string>
using std::string; using std::vector; using std::ostream;
Counter::Counter(int a){
v_ = a;
initialized_ = a;
log_.push_back("Constructor called with a " + std::to_string(a));
}
int Counter::value(){
log_.push_back("value called. returned a " + std::to_string(v_));
return (v_--);
}
ostream & operator<<(ostream & out, Counter & c){
c.log_.push_back("<< called."); //line 1
out << "Counter("<< c.initialized_ << ")#" << c.v_; //line 2
return out;
}
Counter operator+(const Counter & c_one, const Counter & c_two){
Counter c_three(c_one.initialized_ + c_two.initialized_);
c_three.set_v(c_one.get_v()+c_two.get_v());
return c_three;
}
When I compile the file I get bombarded with expected primary-expression before ‘.’ token in line 1 and line 2 of the "<<" operator overloaded function. I really have no idea as to why this is happening. Any help?
What is c? You've defined it as nothing and then you use
c.log_.push_back(...)
Which the preprocessor changes to
.log_.push_back(...)
I'm not sure what you're trying to do but the error clearly states it's looking for an expression before the period, where it appears you have none.

How do I display the contents of a std::vector of my own datatype and display the name on the console using std::copy?

I would like to display the contents of the std::vector<User> using std::copy in a similar way to how I've achieved it through std::for_each in the code below.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class User {
private:
std::string m_sName;
public:
User(std::string sName):m_sName(sName) {}
std::string GetName()const {
return m_sName;
}
};
int main()
{
std::vector<User> vectNames;
vectNames.emplace_back("Jack");
vectNames.emplace_back("George");
vectNames.emplace_back("Jose");
//How can I get std::copy to do what the std::for_each is doing?
std::copy(vectNames.begin(), vectNames.end(), std::ostream_iterator<User>(std::cout, "\n"));
//The following line is what I really would like std::copy to do.
std::for_each(vectNames.begin(), vectNames.end(), [](const User &user) {std::cout << user.GetName() << "\n"; });
}
You can simply overload the ostream operator:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class User {
private:
std::string m_sName;
public:
User(std::string sName):m_sName(sName) {}
std::string GetName()const {
return m_sName;
}
void print(std::ostream& where) const
{ where << m_sName; }
};
/// Overloaded ostream operator
std::ostream& operator<< (std::ostream& out, const User& user)
{
user.print(out);
return out;
}
int main()
{
std::vector<User> vectNames;
vectNames.emplace_back("Jack");
vectNames.emplace_back("George");
vectNames.emplace_back("Jose");
std::copy(vectNames.begin(), vectNames.end(), std::ostream_iterator<User>(std::cout, "\n"));
}
In general I always have an overloaded ostream as part of classes that store and output information.
Because of your comment I am a new programmer and am experimenting with different ideas, I'm posting this answer as an alternative approach which also shows some algorithm that you might enthusiastic about.
I think that std::copy isn't the right tool if what you want to do is both
calling a member function on the objects in a collection, and only after that
copying/printing them to screen
One, and maybe the best, approach is the one in the atru's answer, which basically solves only point 2 with std::copy (and this is something you already knew how to do it, based on your question), and point 1 by overloading <<, which makes the trick.
The alternative I propose is based on the idea that "calling a member function on every object of a collection" is actually a transform operation of that collection. std::transform, however, just like std::copy acts on iterators, not on ranges, so they cannot be easily composed with one another.
Here comes Boost, with boost::copy and boost::adaptors::transformed which allow you to do this:
boost::copy(
vectNames | transformed([](auto const& x){ return x.GetName(); }),
std::ostream_iterator<std::string>(std::cout, "\n")
);
where vectNames is "piped into" transformed, which applies the lambda on every element of the collection, resulting in a new temporary collection, which is the argument to boost::copy. If you were to use std::copy, you would have to store the temporary somewhere, e.g. in temp, before passing to std::copy its iterators temp.begin() and temp.end().
The full example is below. I hope it will give you some insight in different, more functional, approaches.
#include <functional>
#include <iostream>
#include <vector>
#include <string>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
class User {
private:
std::string m_sName;
public:
User(std::string sName):m_sName(sName) {}
std::string GetName()const {
return m_sName;
}
};
int main()
{
std::vector<User> vectNames;
vectNames.emplace_back("Jack");
vectNames.emplace_back("George");
vectNames.emplace_back("Jose");
using boost::adaptors::transformed;
boost::copy(
vectNames | transformed([](auto const& x){ return x.GetName(); }),
std::ostream_iterator<std::string>(std::cout, "\n")
);
}

Look up overloaded operators in outer namespace in class design

How to let a wrapper class in a namespace know that in the outer/global namespace there may exist overloaded operators for the object that it wraps?
Note: I've heard of ADL, or Koenig lookup, but I met a real problem.
The Real Design Problem
I want to design a header-only library. Say I put everything in namespace my. The part related to this question can be simplified to something like a template wrapper item.
// my.hpp
#include <iostream>
namespace my
{
template<typename T>
struct item
{
T thing;
item(T t) : thing(t) {}
};
template<typename T>
std::ostream & operator<<(std::ostream & os, const item<T> & it)
{
os << it.thing;
return os;
}
}
With item what I want to achieve is that:
item<T> wraps a T object (with T object to be provided by user)
If operator<<(std::ostream &, const T &) is not defined in <iostream>, then I assume the user has overloaded operator<<(std::ostream &, const T &), and I want operator<<(std::ostream &, const item<T> &) to call it.
A Concrete User Example
Consider a set of user code that does so for T = std::vector<double>
// user.hpp
// #include guard omitted
#include <iostream>
#include <vector>
std::ostream & operator<<(std::ostream &, const std::vector<double> &);
and
// user.cpp
#include <iostream>
#include <vector>
std::ostream & operator<<(std::ostream & os, const std::vector<double> & v)
{
for (const auto & e : v)
os << e << " | ";
return os;
}
int main()
{
std::vector<double> vec = {3.14, 2.83};
std::cout << my::item<std::vector<double>>(vec);
}
Now if the user put
#include "user.hpp"
#include "my.hpp"
at the beginning of user.cpp, everything would be fine and g++ user.cpp would compile as expected.
However, if the user changed the order and put
#include "my.hpp"
#include "user.hpp"
the compiler would generate an error saying
my.hpp: In function 'std::ostream& my::operator<<(std::ostream&, const my::item<T>&)':
my.hpp:15:23: error: '::operator<<' has not been declared
Certainly I do not want the result to be dependent on the order of #include.
My question is: As a designer of namespace my and wrapper item<T>, what can I do to my and item<T> so that item<T> can correctly spot and call operator<<(std::ostream, const T &) if it is provided by user?
Thank you for your time!
Update: For your information, g++ --version returns
g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0
After reading a question and answer on meta, and following suggestions from comments, I am moving some "updates" in my own question and posting them formally as a self-answer. I am doing so in the hope that this will help someone in future who happen to meet the same kind of problem. Thank you!
As #xskxzr correctly points out in the comment, there is something bad in the user code. To be specific,
it is bad to declare functions/operations whose parameters are all std entities as you cannot add such declarations into std to make use of ADL
In this case, the problem lies on the side of the user, not on the designer.
Now if the user made a change
// user.hpp
#include <iostream>
#include <vector>
// CHANGE: (privately) inherit from std::vector<double>, rather than overload directly
struct DoubleVector : private std::vector<double>
{
using std::vector<double>::vector;
friend
std::ostream & operator<<(std::ostream &, const DoubleVector &);
};
std::ostream & operator<<(std::ostream &, const DoubleVector &);
and
// user.cpp
#include "my.hpp"
#include "user.hpp"
#include <iostream>
#include <vector>
// CHANGE: use a user-defined DoubleVector class
std::ostream & operator<<(std::ostream & os, const DoubleVector & c)
{
for (const auto & e : c)
os << e << " | ";
return os;
}
int main()
{
DoubleVector vec = {3.14, 2.83};
std::cout << my::item<DoubleVector>(vec);
}
Then the user code would compile regardless of the order of #include "my.hpp" and #include "user.hpp".

c++ creating my own toString() method in header file

I am trying to override toString method like it is possible in Java. I am really new to C++, so even though test program using this header file will compile, it could have a lot of mistakes. My goal is to get the point back as string in the form of "(x1, x2, x3....x4)". The amount of coordinates will be changeing from 0 to n. How can I change toString() so that it would not return "test" but would return the coordinates of the point as String?
#ifndef POINT_H
#define POINT_H
#include <iostream>
#include <list>
#include <cmath>
using std::ostream;
using std::list;
using ::std::sqrt;
using namespace std;
template<unsigned short n>
class Point {
public:
list <float> coords;
Point <n>() = default;
Point <n>(list<float> coords){
if (coords.size()!=n) {
throw string ("Vale kordinaatide arv");
}
this-> coords=coords;
}
string toString() const {
return "Test toString";
}
float distanceFrom (Point <n> v){
float s=0;
list<float> coords;
auto it1= coords.begin();
auto it2= v.coords.begin();
while ((it1) != coords.end()){
s+=(*it1 -*it2)*(*it1-*it2);
it1++;
it2++;
}
return sqrt(s);
}
friend std::ostream& operator <<(std::ostream& out, const Point<n>& v)
{
out << "("<<"Test"<<")";
return out;
}
};
#endif

mem_fun_ref: unresolved overloaded function type

The following code won't compile because of "error: no matching function for call to ‘mem_fun_ref()’" (gcc version 4.4.6).
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
class toto
{
char v[10];
public:
toto(char* t) { memcpy(v, t, 9); }
bool test(const char* var) const { return !strncmp(var, v, 9); }
bool test(const string& var) const { return test(var.c_str()); }
};
int main()
{
vector<toto> t;
t.push_back("1");
t.push_back("2");
string name("2");
vector<toto>::iterator it = remove_if(t.begin(), t.end(),
bind2nd(mem_fun_ref(&toto::test), name)); // <= error
t.erase(it, t.end());
return 0;
}
I found a workaround: creating a
bool testZ(const string& var) const { return testZ(var); }
But I can't seem to find the correct template parameters, if that's even possible, to give to mem_fun_ref (or bind2nd?) to make it compile without my workaround.
Is there anyway to achieve this without my workaround, or is the workaround the "preferred" method?
You should be able to cast it according to C++ overloaded method pointer:
bind2nd(mem_fun_ref((bool (toto::*)(const string&) const) &toto::test), name));