Overloaded template operator calling separate class operator - c++

I've got a template class containing a priority queue of other classes, I need to use the priority overloader to call the individual class overloaders to compare based on the individual classes preferences (in this case it's age, in another class it could be price.
I've got absolutely no doubt that I've implemented the operator overloading incorrect so would appreciate the advice.
For example
#include <iostream>
#include <queue>
#include <string>
using namespace std;
class Animal {
public:
Animal();
Animal(string t, int a);
int get_age()const;
bool operator< ( Animal& b) const;
void display()const;
private:
string type;
double age;
};
void Animal::display() const
{
cout << "Type: " << type << " Age: " << age;
}
int Animal::get_age() const
{
return age;
}
Animal::Animal(){}
Animal::Animal(string t, int a)
{
type = t;
age = a;
}
bool Animal::operator< ( Animal& b) const
{
return b.get_age();
}
template<typename T>
class Collection {
public:
Collection();
Collection(string n, string d);
void add_item(const T& c);
private:
priority_queue <T> pets;
string name; // Name of the collection
string description; // Descriptions of the collection
};
template<typename T>
Collection<T>::Collection(){}
template<typename T>
Collection<T>::Collection(string n, string d)
{
name = n;
description = d;
}
template<typename T>
bool operator<(const T& one, const T& two)
{
return one.operator<(two);
}
template<typename T>
void Collection<T>::add_item(const T& c)
{
pets.push(c);
}
int main(){
Animal p1("Dog", 10);
Animal p2("Cat", 5);
Animal p3("Turtle", 24);
Collection<Animal> P("Pets", "My Pets");
P.add_item(p1);
P.add_item(p2);
P.add_item(p3);
cout << endl;
return 0;
}
I get this error and I'm not sure what I need to do to fix it. I've got to keep the class overloader as the single variable (Animal& b).
task.cpp: In instantiation of 'bool operator<(const T&, const T&)
[with T = Animal]':
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_function.h:237:22:
required from 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&)
const [with _Tp = Animal]'
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_heap.h:310:4: required from 'void std::__adjust_heap(_RandomAccessIterator,
_Distance, _Distance, _Tp, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator > >; _Distance = int; _Tp = Animal; _Compare =
std::less]'
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_heap.h:442:4: required from 'void std::make_heap(_RandomAccessIterator,
_RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator > >; _Compare = std::less]'
c:\mingw-4.7.1\bin../lib/gcc/mingw32/4.7.1/include/c++/bits/stl_queue.h:393:9: required from 'std::priority_queue<_Tp, _Sequence,
_Compare>::priority_queue(const _Compare&, const _Sequence&) [with _Tp = Animal; _Sequence = std::vector >; _Compare = std::less]' task.cpp:57:45: required from 'Collection::Collection(std::string, std::string) [with T = Animal;
std::string = std::basic_string]' task.cpp:79:43: required
from here task.cpp:66:30: error: no matching function for call to
'Animal::operator<(const Animal&) const' task.cpp:66:30: note:
candidate is: task.cpp:36:6: note: bool Animal::operator<(Animal&)
const task.cpp:36:6: note: no known conversion for argument 1 from
'const Animal' to 'Animal&' task.cpp: In function 'bool
operator<(const T&, const T&) [with T = Animal]':

Your comparison
bool Animal::operator< ( Animal& b) const
{
return b.get_age(); // returns true always unless age == 0
}
is no comparison and it should take a const parameter. You should have something like
bool Animal::operator< (const Animal& b) const
// ^----------------------- const !
{
return get_age() < b.get_age();
}
Btw you dont need to use a member operator< for the priority queue. Especially if you want to sort objects in different ways I would recommend to not use it, but pass a lambda to the priority_queue. See eg here for an example.

Both of your overloads of < are problematic
bool Animal::operator< ( Animal& b) const
the Animal should also be const. You also need to compare both parameters, otherwise things (such as your priority_queue) that expect < to provide an ordering will have undefined behaviour.
You don't use anything non-public from Animal, so I suggest you change it to
bool operator< (const Animal & lhs, const Animal & rhs)
{ return lhs.get_age() < rhs.get_age(); }
This has the benefit of treating both sides identically, rather than one being implicit.
template<typename T>
bool operator<(const T& one, const T& two)
{
return one.operator<(two);
}
This template matches all types and is entirely superfluous. a < b can call either a member or a free operator <. Just delete this template.

Related

std vector no match for operator ==

I'm stuck at this error:
gcc.compile.c++
Physics/HelicityAmplitude/bin/gcc-4.8.3/debug/HelicityDecayTree.o In
file included from
/cvmfs/cluster/gcc/gcc-4.8.3/include/c++/4.8.3/algorithm:62:0,
from /cluster/compwa_externals/boost_1_55_0/include/boost/move/algorithm.hpp:23,
from /cluster/compwa_externals/boost_1_55_0/include/boost/move/move.hpp:24,
from /cluster/compwa_externals/boost_1_55_0/include/boost/unordered/detail/util.hpp:19,
from /cluster/compwa_externals/boost_1_55_0/include/boost/unordered/detail/buckets.hpp:14,
from /cluster/compwa_externals/boost_1_55_0/include/boost/unordered/detail/table.hpp:10,
from /cluster/compwa_externals/boost_1_55_0/include/boost/unordered/detail/equivalent.hpp:14,
from /cluster/compwa_externals/boost_1_55_0/include/boost/unordered/unordered_set.hpp:17,
from /cluster/compwa_externals/boost_1_55_0/include/boost/unordered_set.hpp:16,
from /cluster/compwa_externals/boost_1_55_0/include/boost/graph/adjacency_list.hpp:21,
from Physics/HelicityAmplitude/HelicityDecayTree.hpp:17,
from Physics/HelicityAmplitude/HelicityDecayTree.cpp:12:
/cvmfs/cluster/gcc/gcc-4.8.3/include/c++/4.8.3/bits/stl_algo.h: In
instantiation of ‘_RandomAccessIterator
std::__find(_RandomAccessIterator, _RandomAccessIterator, const _Tp&,
std::random_access_iterator_tag) [with _RandomAccessIterator =
__gnu_cxx::__normal_iterator >; _Tp =
HelicityFormalism::ParticleState]’:
/cvmfs/cluster/gcc/gcc-4.8.3/include/c++/4.8.3/bits/stl_algo.h:4441:45:
required from ‘_IIter std::find(_IIter, _IIter, const _Tp&) [with
_IIter = __gnu_cxx::__normal_iterato r >; _Tp =
HelicityFormalism::ParticleState]’
Physics/HelicityAmplitude/HelicityDecayTree.cpp:59:61: required from
here
/cvmfs/cluster/gcc/gcc-4.8.3/include/c++/4.8.3/bits/stl_algo.h:166:17:
error: no match for ‘operator==’ (operand types are
‘HelicityFormalism::ParticleState’ and ‘const Helicit
yFormalism::ParticleState’)
if (*__first == __val)
I see that he is asking for a const to non-const comparison of ParticleState. However I don't really understand why he is asking for this comparison. My relevant code is the following:
The header for the class:
class HelicityDecayTree {
boost::adjacency_list<> decay_tree_;
std::vector<ParticleState> particles_;
public:
void createDecay(const ParticleState &mother,
const ParticleStatePair &daughters);
}
And the source for that member function:
void HelicityDecayTree::createDecay(const ParticleState &mother,
const ParticleStatePair &daughters) {
// add particles to the list
unsigned int mother_vector_index;
unsigned int daughter1_vector_index;
unsigned int daughter2_vector_index;
if (std::find(particles_.begin(), particles_.end(), mother)
== particles_.end()) {
mother_vector_index = particles_.size();
particles_.push_back(mother);
}
else {
mother_vector_index = std::distance(particles_.begin(),
std::find(particles_.begin(), particles_.end(), mother));
}
if (std::find(particles_.begin(), particles_.end(), daughters.first)
== particles_.end()) {
daughter1_vector_index = particles_.size();
particles_.push_back(daughters.first);
}
else {
daughter1_vector_index = std::distance(particles_.begin(),
std::find(particles_.begin(), particles_.end(), daughters.first));
}
if (std::find(particles_.begin(), particles_.end(), daughters.second)
== particles_.end()) {
daughter2_vector_index = particles_.size();
particles_.push_back(daughters.second);
}
else {
daughter2_vector_index = std::distance(particles_.begin(),
std::find(particles_.begin(), particles_.end(), daughters.second));
}
// then make the correct inserts into the vector and link appropriately
boost::add_edge(mother_vector_index, daughter1_vector_index, decay_tree_);
boost::add_edge(mother_vector_index, daughter2_vector_index, decay_tree_);
}
And the ParticleState struct:
struct ParticleState {
int particle_id_;
std::string name_;
Spin J_;
Spin M_;
};
Afaiu he should be synthesizing the operator== for two const ParticleStates, but for some reason the find method is asking for a non-const version for 1 argument...
Thx in advance,
Steve
Ok I forgot that the compiler will not synthesize the operator==. So I was just missing
bool operator==(const ParticleState &rhs) const {
...
}

Custom allocator works with vector but not with deque (wrapped within a queue)

I have written a custom allocator that allocates memory in a shared memory segment.
This line of code compiles (and runs) fine:
shp_arr = new (vecmem) vector<shape *,smallocator <shape*> > ;
But this line of code:
shp_queue = new (queuemem) queue< shape *, deque < shape *, smallocator< shape * > > > ;
gives me a number of errors. Here they are:
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h: In
instantiation of ‘std::_Deque_base<_Tp, _Alloc>::_Map_alloc_type std::_Deque_base<_Tp,
_Alloc>::_M_get_map_allocator() const [with _Tp = shape*; _Alloc = smallocator<shape*>;
std::_Deque_base<_Tp, _Alloc>::_Map_alloc_type = smallocator<shape**>]’:
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:549:9:
required from ‘void std::_Deque_base<_Tp, _Alloc>::_M_deallocate_map(_Tp**, std::size_t) [with _Tp =
shape*; _Alloc = smallocator<shape*>; std::size_t = unsigned int]’
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:568:4:
required from ‘std::_Deque_base<_Tp, _Alloc>::~_Deque_base() [with _Tp = shape*; _Alloc =
smallocator<shape*>]’
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:781:15:
required from ‘std::deque<_Tp, _Alloc>::deque() [with _Tp = shape*; _Alloc = smallocator<shape*>]’
file.cpp:233:30: required from here
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:529:53: error:
no matching function for call to ‘smallocator<shape**>::smallocator(const _Tp_alloc_type&)’
/usr/local/lib/gcc/i686-pc-cygwin/4.7.3/../../../../include/c++/4.7.3/bits/stl_deque.h:529:53: note:
candidates are:
In file included from file.cpp:20:0:
smallocator.hpp:41:3: note: smallocator<T>::smallocator(const smallocator<T>&) [with T = shape**;
smallocator<T> = smallocator<shape**>]
smallocator.hpp:41:3: note: no known conversion for argument 1 from ‘const _Tp_alloc_type {aka const
smallocator<shape*>}’ to ‘const smallocator<shape**>&’
smallocator.hpp:40:3: note: smallocator<T>::smallocator() [with T = shape**]
smallocator.hpp:40:3: note: candidate expects 0 arguments, 1 provided
The interface to smallocator looks like this:
template <typename T>
class smallocator: public std::allocator<T>
{
public:
typedef size_t size_type;
typedef T* pointer;
typedef const T* const_pointer;
template<typename _Tp1>
struct rebind
{
typedef smallocator<_Tp1> other;
};
pointer allocate(size_type n, const void *hint=0)
{
...
}
void deallocate(pointer p, size_type n)
{
...
}
smallocator() throw(): std::allocator<T>() { std::cout <<"Hello allocator" <<std::endl;}
smallocator(const smallocator &a) throw(): std::allocator<T>(a) { }
~smallocator() throw() { }
};
Does anyone know what the problem is? Thanks!
You did not provide the following constructor for your smallocator :
template <class U>
smallocator(const smallocator<U>& a) throw();
You need all three :
smallocator() throw();
smallocator(const smallocator& a) throw();
template <class U>
smallocator(const smallocator<U>& a) throw();

How to sort a std::set with const getters

I have a std::set container whose elements are objects of the following class:
class LaneConnector {
public:
const Lane* getLaneFrom() const {
return From;
}
const Lane* getLaneTo() const {
return To;
}
private:
Lane* From;
Lane* To;
}
and my comparator function is as follows:
struct MyLaneConectorSorter {
bool operator() (LaneConnector * c, LaneConnector * d)
{
Lane* a = const_cast<Lane*>(c->getLaneFrom());
Lane* b = const_cast<Lane*>(d->getLaneFrom());
return (a->getLaneID() < b->getLaneID());
}
} myLaneConnectorSorter;
Now when I try to sort the elements in the set with:
//dont panic, the container just came through a const_iterator of a std::map :)
const std::set<LaneConnector*> & tempLC = (*it_cnn).second;
std::sort(tempLC.begin(), tempLC.end(), myLaneConnectorSorter);
I get a frenzy of errors starting with the following lines, Appreciate if you help me solve this problem.
Thanks:
/usr/include/c++/4.6/bits/stl_algo.h: In function ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::_Rb_tree_const_iterator<LaneConnector*>, _Compare = {anonymous}::MyLaneConectorSorter]’:
/home/.../dev/Basic/shared/conf/simpleconf.cpp:1104:65: instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: error: no match for ‘operator-’ in ‘__last - __first’
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_iterator.h:321:5: note: template<class _Iterator> typename std::reverse_iterator::difference_type std::operator-(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/usr/include/c++/4.6/bits/stl_iterator.h:378:5: note: template<class _IteratorL, class _IteratorR> typename std::reverse_iterator<_IteratorL>::difference_type std::operator-(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: std::ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<LaneConnector*>’ to ‘const std::_Bit_iterator_base&’
First, you cannot sort an std::set. It is a sorted structure, sorting happens upon construction or insertion.
Second, you can construct an std::set with your own sorting functor, and you can avoid unnecessary const_casts by making it take const pointers:
struct MyLaneConectorSorter {
bool operator() (const LaneConnector* lhs, const LaneConnector* rhs) const
{
// you may want to put some null pointer checks in here
const Lane* a = lhs->getLaneFrom();
const Lane* b = rhs->getLaneFrom();
return a->getLaneID() < b->getLaneID();
}
};
and instantiate the set like this:
std::set<LaneConnector*, MyLaneConectorSorter> s(MyLaneConectorSorter());
or, if you want to construct it from a different set, with a different ordering,
std::set<LaneConnector*> orig = ..... ;
....
std::set<LaneConnector*, MyLaneConectorSorter> s(orig.begin(), orig.end(), MyLaneConectorSorter());

Using STL algorithms with shared_ptr, function objects

I have a set of shared_ptr, and I'd like to use remove_copy_if with a custom function object for the predicate. I didn't know the "best" way to do it. Right now, I've got this working:
class CellInCol : public std::unary_function<const std::shared_ptr<Cell>,
bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
bool operator() ( const std::shared_ptr<Cell> &a ) const
{
return ( a->GetX() == _col );
}
private:
size_t _col;
};
typedef std::set<std::shared_ptr<Cell>, CellSorter> Container;
Container _grid;
// initialization omitted...
Puzzle::Container Puzzle::GetCol( size_t c )
{
Cell::Validate( c, 1, 9 );
Container col;
std::remove_copy_if( _grid.begin(), _grid.end(),
std::inserter( col, col.begin() ),
std::not1( CellInCol( c ) ) );
return col;
}
I decided to do const references to shared_ptr because the object won't hold on to the pointer and this just seemed more efficient than an extra copy of the shared_ptr.
It seems like it would be better to just take const references to the objects, but I couldn't get it to compile. I changed it to this, but no luck:
class CellInCol : public std::unary_function<const Cell,
bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
// note use of const ref to shared_ptr's
bool operator() ( const Cell &a ) const
{
return ( a.GetX() == _col );
}
private:
size_t _col;
};
Here is the output from g++:
In file included from /usr/include/c++/4.4/algorithm:62,
from /usr/include/c++/4.4/valarray:41,
from Puzzle.h:5,
from Puzzle.cpp:2:
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellInRow>]’:
Puzzle.cpp:100: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellInRow>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellInRow]
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellInCol>]’:
Puzzle.cpp:110: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellInCol>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellInCol]
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellInBlock>]’:
Puzzle.cpp:121: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellInBlock>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellInBlock]
/usr/include/c++/4.4/bits/stl_algo.h: In function ‘_OIter std::remove_copy_if(_IIter, _IIter, _OIter, _Predicate) [with _IIter = std::_Rb_tree_const_iterator<std::shared_ptr<Sudoku::Cell> >, _OIter = std::insert_iterator<std::set<std::shared_ptr<Sudoku::Cell>, Sudoku::CellSorter, std::allocator<std::shared_ptr<Sudoku::Cell> > > >, _Predicate = std::unary_negate<Sudoku::<unnamed>::CellIsNeighbor>]’:
Puzzle.cpp:154: instantiated from here
/usr/include/c++/4.4/bits/stl_algo.h:938: error: no match for call to ‘(std::unary_negate<Sudoku::<unnamed>::CellIsNeighbor>) (const std::shared_ptr<Sudoku::Cell>&)’
/usr/include/c++/4.4/bits/stl_function.h:357: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = Sudoku::<unnamed>::CellIsNeighbor]
make: *** [Puzzle.o] Error 1
Is there another way to do it, or any suggestions?
First of all, since you're using the C++0x features (std::shared_ptr), it makes sense to use std::copy_if() to avoid having to call std::not1.
The first functor you wrote works, and a minimal compilable example would be something like this: https://ideone.com/XhuNu
The second functor does not work, as the compiler points out, due to mismatch between its argument_type (which is const Cell) and the argument that it is being called with, which is const std::shared_ptr<Cell>&.
It's simply not what the container contains! For all it knows at this point, those Cell objects may not even be copyable.
The second functor would indeed be a better thing to use if the container is a set of Cells, not a set of shared pointers to Cells. It is considered good design to avoid shared ownership of objects anyway.
Example code that would compile with the second functor
#include <set>
#include <functional>
#include <algorithm>
#include <iostream>
struct Cell {
int mX;
Cell(int x) : mX(x) {}
size_t GetX() const { return mX;}
};
struct CellSorter {
bool operator()(const Cell& l, const Cell& r) const
{
return l.GetX() < r.GetX();
}
};
// your second functor begins
class CellInCol : public std::unary_function<const Cell,
bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
// note use of const ref to shared_ptr's
bool operator() ( const Cell &a ) const
{
return ( a.GetX() == _col );
}
private:
size_t _col;
};
// your second functor ends
int main()
{
typedef std::set<Cell, CellSorter> Container;
Container _grid = {Cell(1), Cell(2), Cell(7), Cell(10)};
Container col;
size_t c = 7;
std::remove_copy_if( _grid.begin(), _grid.end(),
std::inserter( col, col.begin() ),
std::not1( CellInCol( c ) ) );
std::cout << "col has " << col.size() << " elements\n"
<< "the first element is " << col.begin()->GetX() << '\n';
}
test run: https://ideone.com/kLiFn
You could use boost::make_indirect_iterator to make std::remove_copy_if work on the Cells instead of the shared_ptrs. However, since the algorithm would be working on the Cells directly, the output iterator would also have to take Cells and not shared_ptrs. Which means the output collection would have to be a collection of Cells.
If you want to store shared_ptrs, you'd have to transform the predicate somehow. You can use boost::lambda to do just that.
Cubbi's example modified to use boost::lambda:
#include <memory>
#include <set>
#include <functional>
#include <algorithm>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
struct Cell {
int mX;
Cell(int x) : mX(x) {}
size_t GetX() const { return mX;}
};
struct CellSorter {
bool operator()(const boost::shared_ptr<Cell>& l, const boost::shared_ptr<Cell>& r) const
{
return l->GetX() < r->GetX();
}
};
class CellInCol : public std::unary_function<Cell, bool>
{
public:
CellInCol( size_t col ) : _col( col ) {}
// note use of const ref to shared_ptr's
bool operator() ( const Cell &a ) const
{
return ( a.GetX() == _col );
}
private:
size_t _col;
};
int main()
{
typedef std::set<boost::shared_ptr<Cell>, CellSorter> Container;
Container _grid;
_grid.insert( boost::shared_ptr<Cell>(new Cell(1)));
_grid.insert( boost::shared_ptr<Cell>(new Cell(2)));
_grid.insert( boost::shared_ptr<Cell>(new Cell(7)));
_grid.insert( boost::shared_ptr<Cell>(new Cell(10)));
Container col;
size_t c = 7;
std::remove_copy_if(
_grid.begin(),
_grid.end(),
std::inserter( col, col.begin() ),
!boost::lambda::bind(CellInCol(c), *boost::lambda::_1) // <------ :^)
);
std::cout << "col has " << col.size() << " elements\n"
<< " the first element is " << (*col.begin())->GetX() << '\n';
}
(ideone's C++0x compiler doesn't know it's boost, so I changed std::shared_ptr to boost::shared_ptr, but that should make no difference)
http://www.ideone.com/mtMUj
ps:
I decided to do const references to shared_ptr because the object won't hold on to the pointer and this just seemed more efficient than an extra copy of the shared_ptr.
Yes, you should (almost) always pass shared_ptrs as reference-to-const, it makes a huge difference. Copying a shared_ptr on a platform with threads means at least one atomic instruction (CAS, atomic-increment or something similar), and those can be rather expensive. (And of course destroying the copy will be equally expensive)
The only exception I can think of would be if the function will copy the shared_ptr. In that case you could either take it by value and use swap() to "copy" it, or provide an rvalue-reference overload. (If the function doesn't always copy the shared_ptr, the rvalue-reference overload would be the preferred solution).
Of course it doesn't make a big difference if the function is expensive anyway, but if it's a very cheap function that might get inlined and is called in a thight loop, the difference can be quite noticeable.

object in a set iterator

I can get a method of a class in a set iterator ?
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print(){
std::cout << name << std::endl;
}
bool operator < (const student & s1){ return true;}
bool operator = (const student & s1){ return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
(*it).print() ;
}
I get this error
students.cpp: In function ‘int main()’:
students.cpp:22: error: passing ‘const student’ as ‘this’ argument of ‘void student::print()’ discards qualifiers
/usr/include/c++/4.2.1/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = student]’:
/usr/include/c++/4.2.1/bits/stl_tree.h:982: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = student, _Val = student, _KeyOfValue = std::_Identity<student>, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
/usr/include/c++/4.2.1/bits/stl_set.h:307: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = student, _Compare = std::less<student>, _Alloc = std::allocator<student>]’
students.cpp:18: instantiated from here
/usr/include/c++/4.2.1/bits/stl_function.h:227: error: passing ‘const student’ as ‘this’ argument of ‘bool student::operator<(const student&)’ discards qualifiers
with
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
now work!! O_o',
#include <iostream>
#include <string>
#include <set>
class student{
public:
student(std::string n){
name=n;
}
void print() const {
std::cout << name << std::endl;
}
bool operator<(const student & s1) const { return true;}
bool operator==(const student & s1) const { return true;}
private:
std::string name;
};
int main(){
std::set<student> studs;
studs.insert(student("name01"));
studs.insert(student("name02"));
std::set<student>::iterator it;
for(it = studs.begin(); it != studs.end(); it++)
it->print() ;
}
You need to add a const qualifer to your print member function:
void print() const
{
std::cout << name << std::endl;
}
Objects in an std::set are necessarily const, since they are used as keys. When an object (or reference) is constant, you can only call member functions of that object which are declared with the const qualifier.
You also want const qualifiers on both the == and < operator overload functions. (And don't forget to change = to == as pointed out in the comments.)
Yes, though it->print() is more intuitive.
A naive world-view is that iterators are a bit like pointers. There is more to it than that, as explained here.
The most obvious form of iterator is a
pointer: A pointer can point to
elements in an array, and can iterate
through them using the increment
operator (++). But other forms of
iterators exist. For example, each
container type (such as a vector) has
a specific iterator type designed to
iterate through its elements in an
efficient way.
You want operator==, not operator=.
Your operator< definition violates the requirements of std::set, and is inconsistent with your operator<. That is, according to your operator<, nothing is equivalent, but according to your operator==, everything is equal. Operator< should define a irreflexive, transitive, and asymmetric (for non-equivalent values) relation.
Objects in a set are necessarily const, and so to call a function on such an object that function must be declared with the const qualifier. Specifically, print() should be declared void print() const.
Similarly, operator< should be declared with the const qualifier. std::set requires that operator< can be called with const objects. Another valid option would be to make operator< a non-member function and to take both objects by value (bad) or const reference (good).
While not required in your example, operator== should also be declared with the const qualifier.
Write your print() function like this:
void print() const //<---- note this 'const'
{
std::cout << name << std::endl;
}
Now your code should work now. :-)
By the way, such functions with const keyword appearing on the right side, are called const member function, as they cannot change any member-data of the class.
See this FAQ: [18.10] What is a "const member function"?
#include <iostream>
#include <set>
using namespace std;
class Boxer{
public:
string name;
int strength;
};
struct Comp{
bool operator()(const Boxer& a, const Boxer& b){
return a.strength > b.strength;
}
};
int main(){
Boxer boxer[3];
boxer[0].name="uday", boxer[0].strength=23;
boxer[1].name="manoj", boxer[1].strength=33;
boxer[2].name="rajiv", boxer[2].strength=13;
set< Boxer, Comp> s;
s.insert(boxer[0]);
s.insert(boxer[1]);
s.insert(boxer[2]);
set< Boxer, Comp>::iterator it = s.begin();
Boxer b = *it;
cout<<b.name;
//result is Manoj
return 0;
}