I have a little problem, which the Visual Studio compiler don't seem to be bothered by, but do in eclipse and g++.
I have 2 classes, Card and CardDeck. I do have the operator <= for 2 Carddecks as parameters and do not for 2 cards. I have a converting ctor, which converts Card to a Deck.
So the problem is when I do:
card1 <= card2
Which does work fine in visual, as it converts the left part to deck, then converts the right and then does the comparing.
In g++ it says:
no match for 'operator<=' (operand types are 'Card' and 'Card')
But there shouldn't be one. as I said I want the convert ctor would convet both sides and do the compare?
Any explanation and solution for this ?
Edit(the operator and ctor declaration and code):
CardDeck(const Card&);
friend bool operator<=(const CardDeck&, const CardDeck&);
CardDeck::CardDeck(const Card& card){
_Deck.push_back(card);
}
Here's a quick&dirty of what I think you are trying to do:
#include <iostream>
struct Element
{
int x;
Element() :x(0) {}
virtual ~Element() {}
};
struct Container
{
Element elems[10];
int n;
Container() { n=0; }
Container(const Element &e) { elems[0]=e; n=1; }
virtual ~Container() {}
friend bool operator<=(const Container &l, const Container &r);
};
bool operator<=(const Container &l, const Container &r)
{
if (l.n<=r.n) { std::cout << "less/equ\n"; return true; }
else { std::cout << "greater\n"; return false; }
}
int main(int argc, const char *argv[])
{
//Container container;
Element a, b;
if (a<=b) std::cout << "okay\n"; else std::cout << "fail\n";
return 0;
}
It works fine with gcc.
Deck(card1) <= Deck(card2)
Make operator<= (operand types are 'Card' and 'Card') override cause you use(mean) that in card1 <= card2 expression. Your code have architecture errors.
Update:
struct Card
{
bool operator<( const Card& right ) const;
};
struct Deck
{
std::vector<Card> m_arr;
Deck() = default;
Deck( const Card& conversion )
{
m_arr.push_back( conversion );
}
bool operator<( const Deck& right ) const;
};
bool Card::operator<( const Card& right ) const
{
return false;
}
bool Deck::operator<( const Deck& right ) const
{
bool result = false;
if(m_arr.size() < right.m_arr.size())
{
result = true;
}
else if(!m_arr.empty() && m_arr.size() == right.m_arr.size() )
{
result = true;
std::vector<Card>::const_iterator it = right.m_arr.begin();
std::vector<Card>::const_iterator it2 = m_arr.begin();
for(; it2 != m_arr.end(); ++it, ++it2 )
{
if((*it) < (*it2))
{
result = false;
break;
}
}
}
return result;
}
Related
I'm testing std::set with a custom comparator. But I see the same object getting inserted twice.
Following is the object class:
class Info
{
public:
Info(string n, string oN, int dom):
name(n),
objName(oN),
domain(dom)
{}
void setName(std::string n) { name = n;}
void setObjName(std::string n) { objName = n;}
void setDomain(int dom) { domain = dom; }
std::string getName() const { return name;}
std::string getObjName() const { return objName;}
int getDomain() const { return domain;}
private:
std::string name;
std::string objName;
int domain;
};
Following is my custom comparator:
struct InfoCmp {
bool operator() (const Info &lhs, const Info &rhs) const {
if((lhs.getName() < rhs.getName()) || (lhs.getObjName() < rhs.getObjName()) || (lhs.getDomain() < rhs.getDomain()) ){
return true;
}
return false;
}
};
Following is the usage:
Info rst1("rst1", "rstObj1", 1);
Info rst2("rst2", "rstObj2", 2);
Info rst3("rst1", "rstObj3", 3);
std::set<Info,InfoCmp> resetSet;
resetSet.insert(rst1);
resetSet.insert(rst2);
resetSet.insert(rst3);
resetSet.insert(rst1);
resetSet.insert(rst2);
resetSet.insert(rst3);
I see rst2 inserted twice, but it shouldn't be as per my comparator.
I see that you've come up with your own solution, after recognizing from the comments that your original did not impose a strict object ordering as required by set. Here's a different version that only requires operator< and not operator==, making it consistent with the classes and algorithms of the standard library. It also simplifies things if you're e.g. doing a case insensitive comparison.
struct InfoCmp {
bool operator() (const Info &lhs, const Info &rhs) const {
if(lhs.getName() < rhs.getName())
return true;
if(rhs.getName() < lhs.getName())
return false;
if(lhs.getObjName() < rhs.getObjName())
return true;
if(rhs.getObjName() < lhs.getObjName())
return false;
return lhs.getDomain() < rhs.getDomain();
}
};
struct InfoCmp2 {
bool operator() (const Info &lhs, const Info &rhs) const {
return std::make_tuple(lhs.getName(), lhs.getObjName(), lhs.getDomain()) < std::make_tuple(rhs.getName(), rhs.getObjName(), rhs.getDomain());
}
};
This operator can written with make_tuple as well, and working fine.
as suggested by Cory Kramer, adding strict ordering in comparator fixed the problem.
struct InfoCmp {
bool operator() (const Info &lhs, const Info &rhs) const {
if((lhs.getName() < rhs.getName())
|| ( (lhs.getName() == rhs.getName()) && (lhs.getObjName() < rhs.getObjName()) )
|| ( (lhs.getName() == rhs.getName()) && (lhs.getObjName() == rhs.getObjName()) && (lhs.getDomain() < rhs.getDomain()) )){
return true;
}
return false;
}
};
Here's my complete working code
class Point2D
{
protected:
int x, y;
public:
Point2D(int x_, int y_) : x(x_), y(y_)
{
}
int getX() const
{
return x;
}
int getY() const
{
return y;
}
bool operator< (const Point2D & pointObj) const
{
if(x == pointObj.getX() && y == pointObj.getY())
return false;
return pointObj.getX() == x ? true : x < pointObj.getX();
}
};
template<typename T, typename U>
void printSet(const set<T>& setToPrint)
{
set<T, U> pSet;
for(typename set<T>::iterator it = setToPrint.begin(); it != setToPrint.end(); it++)
{
pSet.insert(*it);
}
for(typename set<T,U>::iterator it = pSet.begin(); it != pSet.end(); it++)
{
//here print the element
}
}
int main()
{
set<Point2D> setP2;
setP2.insert(Point2D(1,3));
setP2.insert(Point2D(3,2));
int i = 1;
if(i==1)
{
printSet<Point2D, std::less<Point2D > >(setP2);
i++;
}
if(i==2)
{
printSet<Point2D, std::greater<Point2D > >(setP2);
}
}
It produces a bunch of errors from template code, but I think below is the primary one
/usr/include/c++/5/bits/stl_function.h:377:20: error: no match for ‘operator>’ (operand types are ‘const Point2D’ and ‘const Point2D’)
/usr/include/c++/5/bits/stl_function.h:377:20: note: ‘const Point2D’ is not derived from ‘const std::pair<_T1, _T2>’
What is wrong with the code?
In order to be able to create std::set<Point2D, std::greater<Point2D>>, you need to implement operator> between two objects of type Point2D.
Add a member funtion similar to operator< in the class to resolve the problem.
Suggestion for improvement
The operator< function can be simplified to user fewer compare operations.
bool operator< (const Point2D & pointObj) const
{
if ( x != pointObj.x )
{
return ( x < pointObj.x );
}
return ( y < pointObj.y );
}
The operato> function can be similarly implemented as:
bool operator> (const Point2D & pointObj) const
{
if ( x != pointObj.x )
{
return ( x > pointObj.x );
}
return ( y > pointObj.y );
}
You have implemented the < operator, not the >. C++ is pretty particular about that kind of thing. Implement operator> and you should be all set.
You can do that in terms of operator< if you like:
bool operator> (const Point2D & pointObj) const
{
if(x == pointObj.getX() && y == pointObj.getY())
return false;
return pointObj < this;
}
You can see more examples here.
I need to know how to overload the operator = != and < so I could work with set<set<object> >
I have my class:
class pr{
private:
set<set<e> > pr_;
public:
pr();
~pr();
void set_pr(set<e> a);
pr& operator=(const pr& a) const;
bool operator!=(const pr& a) const;
bool operator<(const pr& a) const;
};
So if I have a set like this: {{1,2,3},{4,5}} where the numbers are objects.
I would like to do operations with the sets in other class like this:
void otherclass::myfunction(){
pr prt; //I create the objects
pr prt_old;
set<e> C1; //I create the subset and fill
set<e> C2;
//C1 and C2 filled here
prt.set_pr(C1); //Insert the set<e> into set<set<e>>
prt.set_pr(C2); //It will fail because i dont know how to compare set<e> < <set<e>
while(prt != prt_old){
prt_old = prt ;
prt = create(prt_old);
}
//...
I tried to overload doing this:
pr& pr::operator=(const pr& a) const{
this->clear();
for(set<set<e> >::iterator it =a.begin();it!=a.end();it++){
for(set<e>::iterator j = it->begin(); j != it->end();j++){
this->set_pr(*j);
}
}
return *this;
}
bool pr::operator!=(const pr& a) const{
if(this->size() != a.size()){
return 1;
}
//Now i don't know how to continue for check if for example
// i had {{1,2},{3,4}} and {{1},{2}}
//this two set have same size but they are differnt
//How could i just iterate through the two sets at same time
// and check if subset have too same size or if the objects inside the subset are equal
//Also i need the operator < to insert a set<e> into a set<set<e> > but how??
//Note: class 'e' has already defined the "operator<" for when I insert objects in the set<e>
//And i order them by a function that return an integrer
To test if one set is contained in the other, you iterate over each member of the first set, and test if it exists in the second set.
bool operator<(const pr& a) const {
for (auto _set : _data) {
if (a._data.find(_set) == a._data.end())
return false;
}
return true;
}
To test if two sets are identical, you test their size is equal, and that one is contained in the other
bool operator==(const pr& a) const {
return _data.size() == a._data.size() && *this < a;
}
But notice that there is no need to define an operator==, because the default one defined by std::set is fine.
Here is a full functioning program:
#include <iostream>
#include <set>
using namespace std;
template <class e>
class pr {
private:
set<set<e> > _data;
public:
void insert(set<e> a) { _data.insert(a); }
bool operator==(const pr& a) const {
return _data.size() == a._data.size() && *this < a;
}
bool operator!=(const pr& a) const { return !(*this == a); }
bool operator<(const pr& a) const {
for (auto _set : _data) {
if (a._data.find(_set) == a._data.end())
return false;
}
return true;
}
};
int main()
{
pr<int> a,b,c;
a.insert(set<int>({ 1 }));
b.insert(set<int>({ 1 }));
b.insert(set<int>({ 1, 2 }));
c.insert(set<int>({ 1, 2 }));
c.insert(set<int>({ 1 }));
std::cout << ((a<b) ? "a<b\n" : "NOT a<b\n");
std::cout << ((b<a) ? "b<a\n" : "NOT b<a\n");
std::cout << ((a==c) ? "a==c\n" : "NOT a==c\n");
std::cout << ((b==c) ? "b==c\n" : "NOT b==c\n");
std::cout << ((a==b) ? "a==b\n" : "NOT a==b\n");
return 0;
}
I'm trying to implement a container in C++ that uses a flat array to store the data but iterates over that data in pairs. Now I could easily change the implementation such that the container holds a vector of std::pair however I want to iterate through pairs starting at element 0 or at element 1.
To illustrate what I want to achieve, if my underlying array looks like:
1,2,3,4,5,6,7,8
I want to define two iterators, one which returns the pairs:
(1,2), (3,4), (5,6), (7,8)
and the second iterator to return the pairs:
(2,3), (4,5), (6,7)
is this possible to do while still allowing the elements of the iterator to be references of the underlying array?
It is possible to write your own iterator, which iterates over the elements. The following question shows some explanations on how that is done:
Custom Iterator in C++.
You can then return the desired values as std::pair and iterate to the next element-pair (by incrementing the counter by 2).
Boost library has got Iterator Adaptor that allows you to wrap other iterator types and change or adapt their functionality. Here's how you could use it for your purpose:
#include <boost/iterator/iterator_adaptor.hpp>
#include <vector>
struct iterator :
public boost::iterator_adaptor<
iterator, // the name of our class, see docs for details
std::vector<int>::iterator, // underlying base iterator
std::pair<int&, int&>, // our value type
boost::forward_traversal_tag // the category you wish to give it
>
{
// need this to convert from vector::iterator to ours
explicit iterator(std::vector<int>::iterator i)
: iterator::iterator_adaptor_(i) {}
value_type operator*()
{
return value_type(
*base_reference(),
*(base_reference()+1)
);
}
};
Example of usage:
std::vector<int> v {1,2,3,4};
iterator it(v.begin());
++it;
(*it).first = 0; // TODO: operator->
(*it).second = 0;
for (int i : v) std::cout << i << ' '; // prints 1 0 0 4
You'll also need to override comparison to properly handle end condition, etc. Hope that helps.
Just thought I'd put in what I actually used in my code. I didn't want to use boost as suggested by #jrok but the type std::pair<int&, int&> in their answer gave me a hint of what was required.
Below is the class that I constructed which uses two iterators. A RepeatIterator that returns pairs starting on even indexes in the underlying data, and a SpacerIterator that returns pairs starting on odd indexes.
class RepeatArray {
typedef std::vector<int> storage_t;
public:
class RepeatIterator {
public:
typedef RepeatIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
RepeatIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
class SpacerIterator {
public:
typedef SpacerIterator self_t;
typedef int value_t;
typedef int& reference_t;
typedef int* pointer_t;
typedef std::pair<reference_t, reference_t> return_t;
SpacerIterator(storage_t::iterator input) : current_pos(input){}
return_t operator *() {
return return_t(*(current_pos), *(current_pos + 1 ));
}
self_t operator++() { self_t i = *this; current_pos += 2; return i; }
self_t operator++(int junk) { current_pos+=2; return *this; }
bool operator==(const self_t& rhs) { return current_pos == rhs.current_pos; }
bool operator!=(const self_t& rhs) { return current_pos != rhs.current_pos; }
bool operator<(const self_t& rhs) { return current_pos < rhs.current_pos; }
bool operator<=(const self_t& rhs) { return current_pos <= rhs.current_pos; }
bool operator>(const self_t& rhs) { return current_pos > rhs.current_pos; }
bool operator>=(const self_t& rhs) { return current_pos >= rhs.current_pos; }
private:
storage_t::iterator current_pos;
};
void add(int start, int end) {
positions.push_back(start);
positions.push_back(end);
}
void dump() {
for (auto i : positions) {
std::cout <<i<<",";
}
std::cout <<std::endl;
}
RepeatIterator repeatBegin(){return RepeatIterator(positions.begin());}
RepeatIterator repeatEnd(){return RepeatIterator(positions.end());}
SpacerIterator spacerBegin(){return SpacerIterator(positions.begin() + 1);}
SpacerIterator spacerEnd(){return SpacerIterator(positions.end() - 1);}
protected:
storage_t positions;
};
And then the tesing program compiled using clang++ -std=c++0x -o testRepeatArray RepeatArray.cpp
int main() {
RepeatArray r = RepeatArray();
r.add(1,3);
r.add(7,12);
std::cout<<"original:"<<std::endl;
r.dump();
std::cout << "Testing Repeat iterator:"<<std::endl;
for (RepeatArray::RepeatIterator it2 = r.repeatBegin(); it2 != r.repeatEnd(); ++it2) {
std::cout << (*it2).first <<","<< (*it2).second << std::endl;
}
std::cout << "Testing Spacer iterator:"<<std::endl;
for (RepeatArray::SpacerIterator it3 = r.spacerBegin(); it3 != r.spacerEnd(); ++it3) {
std::cout << (*it3).first <<","<< (*it3).second << std::endl;
}
std::cout<<"Testing modification:"<<std::endl;
RepeatArray::RepeatIterator it = r.repeatBegin();
(*it).first = 0;
(*it).second = 123;
r.dump();
return 0;
}
I have problem with set. I don't know what I'm doing wrong. Maybe some one of you can help me. So lets begin , the output of my program should be :
Iksinski Adam, Kowalski Jan, Nowak Adam, Nowak Jan,
So its sorted by first string.
And here's my program :
#include <set>
#include <iterator>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
class Person{
public:
Person(){}
Person(string v , string v1):nazw(v),imie(v1){}
bool operator<(const Person & K) const
{
return ((this->getN()>K.getN())?0:1);
//return ((this->getN()<K.getN())?1:0);
}
string getN()const
{
return nazw;
}
/*
bool operator()(Person & K, Person & K1)
{
return ((K->getN()<K1.getN())?1:0);
}
*/
friend ostream& operator<<(ostream & o , const Person&K)
{
o << K.nazw << " " << K.imie;
return o;
}
private:
string nazw,imie;
};
struct cmp
{
bool operator()(const Person &K , const Person &K1)
{
return ((K.getN()<K.getN())?1:0);
}
};
int main()
{
//typedef set<Person> kontener_typ;
typedef set<Person,cmp> kontener_typ;
kontener_typ c;
c.insert(Person("Nowak","Jan"));
c.insert(Person("Nowak","Adam"));
c.insert(Person("Kowalski","Jan"));
c.insert(Person("Nowak","Adam"));
c.insert(Person("Iksinski","Adam"));
std::copy (c.begin(), c.end(), ostream_iterator<Person>(cout, " ,"));
std::cout << std::endl;
}
Ok so in main i can only edit typdef , and copy function ( but I need to use it to output the set).
Like you see i tried to overload operator< in Person (because set compering Person to Person) but it doeasnt work . I also trying with functor but it then the output looks like
Iksinski Adam ,Nowak Adam ,Kowalski Jan ,Nowak Adam ,Nowak Jan ,
So second string should be deleted .
Good luck :).
Your code is using your comparator cmp functor object. There is a bug in it:
struct cmp
{
bool operator()(const Person &K , const Person &K1)
{
// one of these _should_ be K1
return ((K.getN()<K.getN())?1:0);
}
};
I like to name my variables in a way that it becomes clear how they are being compared, for instance:
struct cmp
{
bool operator()(const Person &left , const Person &right)
{
return left.getN() < right.getN();
}
};
This clarifies (for me at least) that the operator is comparing like this: left < right.
However, you also need to sort by "first name" as a secondary criteria, which would make the function look like this:
struct cmp
{
bool operator()(const Person &left , const Person &right)
{
if(left.getN() < right.getN())
return true;
else if(left.getN() > right.getN())
return false;
// assuming the getI() function returns the first name,
// just as the getN() function returns the last name
else if(left.getI() < right.getI())
return true;
else
return false;
}
};
You must compare by both last and first names:
bool operator<(const Person & other) const
{
if ( getN() < other.getN() )
return true;
if ( other.getN() < getN() )
return false;
if ( imie < other.imie() )
return true;
return false;
}
Or, if you want to use struct cmp:
struct cmp
{
bool operator()(const Person &K , const Person &K1)
{
if (K.getN() < K1.getN())
return true;
if(K1.getN() < K.getN())
return false;
if(K.imie < K1.imie) // will need a friend declaration or a getter() func
return true;
return false;
}
}
If you have C++'s std::tie, then the guts of either function gets much simpler:
return std::tie(nazw, imie) < std::tie(other.nazw, other.imie);
return std::tie(K.nazw, K.imie) < std::tie(K1.nazw, K1.imie);