views:

84

answers:

4

I have a question that may have been answered over 9000 times before but I really don't know how to word it, this is what I am going to try.

I've seen in some C++ books and tutorials that when defining your own class which has a iterable value (incrementable) semantics, you can overload operator++ for it (all I'm going t state here I'd guess applies for operator-- as well). The standard way of doing this seems to be:

class MyClass {
    public:
    MyClass& operator++ () {
        increment_somehow();
        return *this;
        }
    ....
    };

Where increment_somehow() well... somehow increments the object's value.

Then, it is possible to define the postfix version of operator++ in a manner like this:

MyClass operator++ (MyClass& it, int dummy) {
    MyClass copy(it);
    ++it;
    return copy;
    }

It is all fine and dandy (I think I got that idiom right), but the problem is that doing all that for each class that defines operator++ quickly becomes tiresome and verbose, so I was thinking that I could take some advantage of a trick that I recently learnt when overloading operators. That is, making use of the <utility> header and a facility inside called rel_ops that I found out about yesterday (I just came back to C++ after four years of being away...):

class MyClass {
    public:
    bool operator== (const MyClass& that) {
        return compare_for_equality_somehow(that);
        }
    bool operator< (const MyClass& that) {
        return compare_for_lessality_somehow(that);
        }
    ....
    using namespace std::rel_ops; // operators >, >=, <=, ! are "magically" defined!
    };

(I just invented the term "lessality" for analogy purposes, my head refuses to come up with the correct mathematical term for some reason...)

I created a simple header <step_ops.hpp> whose content somewhat imitates the std::rel_ops namespace found in the Utility header. Fro what I can see after a couple of compiles, it just works(TM). Can I / Should I use this trick? What are possible pitfalls I could come up against if I create a class and use a using namespace MyLibrary::increment_operators (for example)?

And maybe much, MUCH more important: Have I just reinvented the wheel again, or have I just created a useful small library that could be aggregated to such kinds of projects? Pretty much any experiments that I have tried to do with C++ to get myself back up-to-speed and collaborate stuff seem to already be covered under a boost::do_something facility and it makes me kind of sad that I have spent so much time away.

+3  A: 

Boost provides this functionality in the Boost Operators utility library. Its implementation is a little different, but achieves the same result.

Can I / Should I use this trick?

Use it wherever you can; cutting out redundant and repetitive code is a fundamental principle of refactoring and is a good practice to get into.

Have I just reinvented the wheel again, or have I just created a useful small library that could be aggregated to such kinds of projects?

I guess you could say then that you've reinvented the wheel. I don't think that's necessarily a bad thing, though: I find that if I implement something myself I usually understand it much better and learn a lot through the process.

James McNellis
Thanks for the answer. I selected it as the greenticked. I hadn't considered the fact that it helped me understand the trick much better. I'm also considering Head Geek's advice to reinvent more and more wheels (provided I have the spare time to do so :D ).
Luis Machuca
A: 

Alternatively you could use <template T> it is built right into the c++ language, it allows you to use multiple types for the same code, all you need to do is make sure that for each class there that uses the newly defined operator with class template all methods are defined.

See the documentation for more info about template http://www.cplusplus.com/doc/tutorial/templates/

Jordan
+1  A: 

If you've got the time to spare, and need the experience, reinvent all the wheels you like. I've done several myself, to improve my knowledge of the underlying concepts. It can help a lot.

Head Geek
A: 

Hi, I'm the original poster, just answering to say that I finally registered to StackOverflow. As such I have a new handle. Now saying thanks to the answers, in particular HeadGeek with the motivation issue. Also, to correct myself and folloiwing on tjm's comment, the exact form the code is used is not as I posted. The more correct way of using this method is to bring each operator into the class's own scope via using:

namespace scope {
class MyClass {
  public:
  bool operator== (const MyClass& that) {
    return compare_for_equality_somehow(that);
    }
  bool operator< (const MyClass& that) {
    return compare_for_lessality_somehow(that);
    }
  ....
  // using namespace std::rel_ops; // that one is incorrect
  };
using std::rel_ops::operator=!; // similarly for >, >=, <=
} // end of namespace

If done as in my original post, the header compiles fine, but compilation errors are brought when the header is included in a project that also includes and uses rel_ops somewhere. More importantly, that method would bring all operators for all classes defined in the class's scope -- definitively not desirable. With this approach of explicitly using, only the needed operators are brought into scope, and they are resolved as needed.

Thanks everyone, seeing you soon.

(Also, please, don't upvote this question unless you really feel it has something to offer -- it is nothing new since Boost already has it -- I posted this for dual informative purposes)

Luis Machuca