at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.
I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.
Here is my general idea of my class definition:
class object {
public:
int first;
string second;
object(int f, string s) {
first = f;
second = s;
}
bool operator<(const object &comp) {
return first < comp.first;
}
};
This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.
Here is a short code extract from my main function:
includes ...
//code omitted
int main() {
multiset<object*> mmset;
mmset.insert(new object(10, "test"));
mmset.insert(new object(11, "test"));
return 0;
}
After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.
code extract from the stl:
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.
I would really appreciate it if someone could help me.
Best Greetings
Tom
You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.
It seems like you really just want a multiset<object>:
multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");
Now it will use < to compare the objects themselves.
If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:
auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);
Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.
Thank you for your help. That's seems to be a good solution to solve this problem.
I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :)
I will post it just as information for other seekers with the same problem.
You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content.
The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.
class object {
int first;
string second;
object() { };
object(int f, string s) {
first = f;
second = s;
}
bool operator()(const object *comp1, const object *comp2) const {
return comp1->first < comp2->first;
}
}
The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:
multiset(object*, object) mmset;
You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.
Related
I'm learning vectors and now I've got a problem:
binary ==: no operator found which takes a left hand operand of type 'Object'.
I've found out that there is no mustake after deleting:
vector<Object>::iterator it = find(list.begin(), list.end(), name);
And I don't know what to do.
Maybe you will ask something like this
class Object {
private:
string* name;
vector<string>* facts;
public:
//...
}
class ListOfObjects {
private:
vector<Object> list;
public:
void Realise(string* knowledge);
};
void ListOfObjects::Realise(string* knowledge) {
//...
vector<Object>::iterator it = find(list.begin(), list.end(), name);
//...
}
The problem is given by the fact that std::find utilizes operator== to check if the element you are searching is present in the current selection.
Since you pass a string* then the method searched when compiling the std::find template method is
bool Object::operator==(string* argument) const
which must be implemented, and its implementation would be something like
bool Object::operator==(string* argument) const
{
return *argument == name;
}
But I see potential issues with this solution:
you are searching for element in a collection through a specific field, if this is the predominant way you are using, then another different collection would be better, eg std::unordered_map<string, vector<string>>, which would make everything easier
you are allowed to overload operator== with an argument of a type different from the type you are overloading the operator for, while this works and it can be used it doesn't make much sense in terms of equality since you are comparing two different types
you are working with string* which doesn't make sense most of the time (pass const std::string& if you want to avoid copies)
I think what you'd be looking for if you want to compare objects in that way would be called operator overloading.
Here is a short example:
http://www.learncpp.com/cpp-tutorial/94-overloading-the-comparison-operators/
Take note of how operator== is used
I have the following class:
struct EdgeExtended {
int neighborNodeId;
int weight;
int arrayPointer;
bool isCrossEdge;
};
I want to have a vector of such objects, sort it by neighborNodeId. Then I want to search for a particular neighborNodeId and return a reference to the found object inside the vector by binary search. Previously I used a map for that, so it was something like that:
map<int, EdgeExtended> neighbours;
.....
auto it = neighbours.find(dnodeId);
if (it != neighbours.end()) {
edgeMap = it->second;
}
Instead of
map<int, EdgeExtended> neighbours;
I want to have
vector<EdgeExtended> neighbours;
and retain as much as the old code the same.
I want to benchmark if the vector is faster than the map, since I am building thousands of vectors(or maps) and each vector (map) is relatively small (~10 items). I do not know how to a) make objects sortable by neighborNodeId and b) how to use binary search that searches for a particular member of the class (neighborNodeId). Sorry for the noob question. I am counting on your help.
You need a custom comparator function that takes two EdgeExtended objects and compares the fields you're interested in and that you can pass to both sort and binary_search as a third or fourth argument, respectively.
It can be conveniently done with a lambda function:
auto Comp = [](const EdgeExtended& e1, const EdgeExtended& e2)
{
return e1.neighborNodeId < e2.neighborNodeId;
};
If you stuck pre-C++11, write a class with overloaded operator() instead:
struct Comp {
bool operator()(const EdgeExtended& e1, const EdgeExtended& e2) const
{
return e1.neighborNodeId < e2.neighborNodeId;
}
};
Extending on jrok's answer, if you encounter similar problems more often, a reusable templated comparator which uses any member of a class comes in very handy.
template<class T, class U>
class CompareByMember {
U (T::*mem); // ugly syntax for member pointer of type U in class T
public:
CompareByMember(U (T::*mem)) : mem(mem) {}
bool operator()(const T &a, const T &b) {
return (a.*mem) < (b.*mem); // ugly syntax for member pointer access
}
};
As you can see, the syntax for pointers to class members is pretty strange, but once wrapped in this functor you don't have to care about it. One remaining "issue" is that you'd have to write the template parameters <T, U> each time you want to use this functor. But using type deduction this problem is solved, introducing a little helper function (note that its name is lower case):
template<class T, class U>
CompareByMember<T,U> compareByMember(U (T::*mem)) {
return CompareByMember<T,U>(mem);
}
This results in client code like this:
std::vector<EdgeExtended> v = ...;
std::sort(v.begin(), v.end(), compareByMember(&EdgeExtended::neighborNodeId));
Simple demonstration
For member functions, a similar templated functor can be written, using the only slightly different member function pointer syntax. You can also overload the call operator in the functor to accept raw pointers of T as well as any smart pointer wrapping around T* (using templates again).
I am writing a library in C++ for which I implemented a map wrapper with type erasure. The wrapper is structured as in this wonderful article: http://www.cplusplus.com/forum/articles/18756/.
TLDR:
template<typename K, typename V>
class AnyMap
{
class MapConcept
{
public:
// Lots of pure virtual methods...
// These mimic the intersection of STL and Boost maps' interfaces
// Example:
virtual size_type size() = 0;
};
template<typename ActualMapType>
class MapModel : MapConcept
{
ActualMapType m;
public:
// Implementations of the parent's virtual methods...
// These basically just call the same method on member m.
// Example:
size_type size() { return m.size(); }
};
MapConcept* mapConcept;
public:
// Again, the STL and Boost maps' interface methods
// Example:
size_type size() { return mapConcept->size(); }
};
I'm not sure whether I will expose this map as part of the finished library or tuck it away as a helper class, but either way I'm wondering what do with the assignment operator.
Currently, I have something like this:
AnyMap& AnyMap::operator=(const AnyMap& other) {
delete mapConcept;
mapConcept = other.mapConcept->clone();
return *this;
}
This means that if I create two maps with say an STL's map and a Boost's unordered_map and then assign one to the other, both will now have the same map type underlying them.
std::map<string, int> stlMap;
boost::unordered_map<string, int> boostMap;
// insert some stuff into maps
AnyMap<string, int> stlAnyMap( stlMap );
AnyMap<string, int> boostAnyMap( boostMap );
stlAnyMap = boostAnyMap;
// now stlAnyMap has a copy of boostMap
So, this makes some sense because the contents of the map assigned to are what's expected. However, I suspect that usually the map types will differ by one of the type arguments with default values (such as Hash in Boost::unordered_map). So, maybe it should retain the underlying map type. I think, this can be done with something like the following:
AnyMap& AnyMap::operator=(const AnyMap& other) {
mapConcept->clear();
mapConcept->insert( other.mapConcept->begin(), other.mapConcept->end() );
return *this;
}
This should work because of the templated insert method:
template <class InputIterator>
void insert (InputIterator first, InputIterator last);
By the way, if anyone is wondering how I dealt with the iterators: I used Thomas Becker's any_iterator - http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html.
So, what do you guys think? I'm leaning toward the latter approach, but I'd like to hear any arguments for either side.
Thanks in advance!
EDIT: Here is the first argument against (perhaps, you could tell me how important this is): the contents of one map type might now map one-to-one to another map if one predicate distinguishes two keys in the map while the other considers them the same.
Do you want the map wrapper to have value semantics or not? That will determine how deep the copy has to be. In any case, the implementation of other.mapConcept->clone() will be polymorphic (this is, after all, the essence of the C++ type erasure technique) and result in a dispatch to a call in the MapModel subclass that looks like this
virtual MapModel *clone() { return new MapModel(m); } // covariant return type
So everything boils down to what ActualMapType's copy constructor does (since the member variable m will be a copy.)
Since the technique was invented to get value semantics, I think retaining that feature is consistent with the principle of Least Surprise. Moreover, the point is to have a fixed interface. The implementation (STL or boost or whatever) is irrelevant by design, so there is little point in trying to retain the implementation in any particular object instance.
Incidentally your implementation of operator= for the "standard" case is not exception safe. The copy-and-swap idiom (perhaps with a custom swap() method) works better
AnyMap( AnyMap const& other )
: mapConcept( other.mapConcept ? other.mapConcept->clone() : 0)
{}
AnyMap& operator= ( AnyMap rhs ) // note temporary: invokes copy constructor
{ std::swap( mapConcept, rhs.mapConcept ) ; return *this; }
I have a class cl1:
class c1
{
long double * coords;
...
}
I also have a second class cl2:
class cl2
{
vector<cl1*> cl1_vec;
unsigned int d;
...
}
I would like to sort cl1_vec, from cl2, based on coords[d], using the sort function for vectors.
So i could have something like
sort(cl2_inst->cl1_vec.begin(),cl2_inst->cl1_vec.end(), ??? );
I tried approches like
sort the 'std::vector' containing classes
C++ std::sort with predicate function in Class
but i couldn't make my way to solving this.
Thanks for any help that comes this way.
The code i've tried:
class cl1 {
public:
long double* coords;
cl1(long double *, unsigned int);
cl1();
cl1(const cl1& orig);
virtual ~cl1();
};
class cl2 {
public:
unsigned int d;
vector<cl1*> cl1_vec;
//the srting functions
static bool compareMyDataPredicate(cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
};
// declare the functor nested within MyData.
struct compareMyDataFunctor : public binary_function<my_point*, my_point*, bool>
{
bool operator()( cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
}
};
...
...
}
then in main
std::sort(cl2_inst->cl1_vec.begin(),cl2_inst->cl1_vec.end(),cl2::compareMyDataPredicate() );
The error is because you are accessing a non-static member d from a static context of the comparator function. Use the second approach, in the following way:
Provide a constructor to that struct, which takes a parameter unsigned int and sets a member to that value.
Create an object of type compareMyDataFunctor, and pass in the value of d to the constructor.
Use this object for sorting (3rd argument to std::sort)
I am not sure about the problems, because you were not precise enough about what exactly "does not work" means in your case (does not compile, does compile but does not sort etc). In case it does not compile (most likely guess) you did not post the error messages, which also makes finding and explaining the problem very hard.
Here are some guesses based on the code you posted:
Both static function as well as the functor use the member d to decide which column to sort on. However d is an instance variable, so it is not available for anything which is static. Neither the functor nor the static member function would know which of the possible ds to use, as there is one d per instance.
The best way to do this without resorting to C++11 features (lamdas) is to provide a constructor to the functor which takes the d you are planning to use. Something like this:
struct compareMyDataFunctor : public binary_function<cl1*, cl1*, bool>
{
compareMyDataFunctor( unsigned int d ) : d( d ) {}
bool operator()( cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
}
unsigned int d;
};
This should do the trick.
There are some more things wrong with the code you posted though:
Arrays should be indexed using type size_t not a unsigned int. Same goes for std::vectors
The types in the std::binary_function instantiation do not match the actual types in the method (may be a problem of reducing the code).
Do not use using namespace std (I assume you do from the declarations in your code).
Functors such as these should take parameters as const-reference, not by value.
That's all I can think of. Next time try to present short, self contained, complete examples, then people will not have to resort to guessing.
right now i am learning C++, and now I know the basic concept of template,
which act just like a generic type,
and i found almost every c++ program used template,
So i really want to know when are we supposed to use template ?
Can someone conclude your experience for me about c++ template ?
When will you consider to use template ?
Supplement:
if we defined such function
template <class myType>
myType GetMax (myType a, myType b) {
return (a>b?a:b);
}
but we want to pass a object(self-defined class) for comparison, how can we implement ?
Supplement2:
in the answer below, someone have wrote this sample code
template <class myType>
const myType& GetMax (const myType& a, const myType& b) {
return (a<b?b:a);
}
template <class myType, class Compare>
const myType& GetMax (const myType& a, const myType& b, Compare compare) {
return (compare(a,b)?b:a);
}
is this correct ? can we just pass a function name as a parameter of class myType ?
G'day,
Simple answer is when you want the behaviour to remain the same independent of the type being used to instantiate the class.
So a stack of ints will behave in the same way as a stack of floats will behave as a stack of MyClass objects.
Inheritance and base classes are used when you want to allow specialisation of the behaviour.
So say you have a base class called Animal and it has a member function called makeSound(). You have no idea which sound every animal will make so you make the makeSound member function a virtual function. In fact, because there is no default sound for all animals you have no idea what to have as default behaviour so you would declare this member function as a pure virtual function.
This then tells anyone making an instance of a derived class, for example a Lion class, that they must provide an implementation the makeSound member function which will provide a roar in some way.
Edit: I forgot to add that this is one of the articles in Scott Meyers's excellent book "Effective C++" (sanitised Amazon link) which I highly recommend.
HTH
cheers,
Basically when you want to create a generic class that can handle the solution for multiple types of classes, without having to have a parent-class for all the classes you want to support.
You can just give the class along with which you want to work with (best example would be a container, which can store any type that you pass along with the creation)
//----- the container
template <class T>
class Stack
{
public:
T* stackPtr;
}
//----- example
void main()
{
typedef Stack<float> FloatStack;
typedef Stack<int> IntStack;
}
Now you can store floats and ints with the same class without having to write a specific class for each type.
Short answer: if there is no use for it: don't.
If it seems to solve a problem (code reuse on different types,...), first implement and debug without templates and then add template parameters.
Before STL/boost, they were nice to make containers.
In the example you provided, everything is OK as long as operator > is defined for the data type whose instances you're comparing.
For example, if you define the following class:
class fraction
{
private:
int _num, _den;
public:
fraction(int num, int den)
{
if (den >= 0)
{
_num = num;
_den = den;
}
else
{
_num = -num;
_den = -den;
}
}
fraction(const fraction &f)
{
_num = f._num;
_den = f._den;
}
bool operator > (const fraction &f) const
{
return (_num * f._den) > (f._num * _den);
}
bool operator == (const fraction &f) const
{
return (_num * f._den) == (f._num * _den);
}
};
Then you can use your template function with instances of this class.
int main(int argc, char* argv[])
{
fraction a(1,2); // 0.5
fraction b(3,4); // 0.75
assert(GetMax/*<fraction>*/(a,b) == a);
return 0;
}
Re: supplement. If you want to pass a comparison function, you could provide another overload:
template <class myType>
const myType& GetMax (const myType& a, const myType& b) {
return (a<b?b:a);
}
template <class myType, class Compare>
const myType& GetMax (const myType& a, const myType& b, Compare compare) {
return (compare(a,b)?b:a);
}
Samle usage: to compare C-style strings:
bool c_strings_less(const char* a, const char* b)
{
return std::strcmp(a, b) < 0; //is a less than b
}
const char* greater = GetMax("hello", "world", c_strings_less);
This is how the std::max algorithm works. (I also made a few modifications, e.g it is customary in C++ that predicates define "less-than" comparison.)
Or if you asked, how GetMax would work for arbitrary user-defined types, then those must overload operator> or your function would result in a compile error.
When you need to parameterize concept represented by a class.
For example, if you have a class that represent a way to manage a type of object
class MyThingManager
{
void add( MyThing& mything );
//...
};
...maybe you need later to use exactly the same behaviour in a new type but managing a different type. Then you have the choice to use copy/paste/replace --that would lead hell opening under your feet immediately-- or make your class have a type to manage as parametter :
template< class ThingType >
class ThingManager
{
void add( ThingType& thing );
//...
};
That way you don't duplicate code.
Another concern is when you want some function call to be compatible with any parameter that have the required semantic :
template< class MyType >
void addPi( MyType& value )
{
value += PI;
}
That way you (again) don't have to duplicate code for each types possible in parametters.
It's not called "generic programming" for nothing.
Those are simple cases, but more complex cases exists, when you want to do some meta-programming. If you want to go there, please read at least one book before writing hell code. I recommand "C++ Template Meta-Programming" for that and the excellent "Modern C++ Design" book for more advanced template usage like Policy pattern ans other well known.
Answering the second question(
but we want to pass a object(self-defined class) for comparison, how can we implement?)
If you want to use your own class in a template function using the
operator >.
Your class need only to define this operator or function.
The important part is that your class need to define the same
the operator or function the template uses.
/Tobias
if you dont know the type of your variable or you want to do same thing for many types of variables, you can use template...
if you want to add 2 int, you want to get an int for return
if you want to add 2 double, you want to get an double for return
so you use template for this..
Template provide the way to parametrize on KNOWN AT COMPILE TIME quantities. Note that it can be a type (std::vector will contain only integers) but they can also be values:
template <int N, typename T > class MyType
is templatized both on an integer and a type, and MyType<2, int> will be a different type from MyType<3, int>.
Furthermore, templates allow for Template Metaprogramming: that is the compiler executes a program at compile time. There is a fascinating example by Erwin Unruh for computing primes at compile time.
Look at http://ubiety.uwaterloo.ca/~tveldhui/papers/priority.html for a small bit of history.
It's important to note that it's perfectly alright to not write your own templates. If you're not sure why you might need them, then you probably don't need them. Templates are a very powerful tool, but they are not always the best solution.
On any common development platform, the standard library provides a high-quality implementation of many of the old-school, traditional uses of templates. Using the standard library classes and functions doesn't require writing new templates. For instance, it provides std::max(), which is the same as your example.