Overloading unary minus for use in function calls

Discussion in 'C++' started by Matthew Cook, Dec 20, 2006.

  1. Matthew  Cook

    Matthew Cook Guest

    I would like to overload the unary minus operator so that I can negate
    an instance of a class and pass that instance to a function without
    creating an explicit temporary variable. Here is an example:

    #include <iostream>
    using namespace std;

    class Object
    {
    public:
    int number;
    Object(int value);
    const Object operator- ();
    //friend const Object operator- (const Object& o);

    };

    Object::Object(int value) :
    number (value)
    {}

    const Object Object::eek:perator- ()
    {
    cout << "using class minus" << endl;
    number = -number;
    return *this;
    }
    /*
    const Object operator- (const Object& o)
    {
    cout << "using friend minus" << endl;
    return Object(-o.number);
    }*/

    void useAnObject(Object& o)
    {
    cout << "using object with number: " << o.number << endl;
    }

    int main(int argc, char* argv[])
    {
    Object a(4);
    useAnObject(-a); // does not work but would like it to
    //Object b = -a; // works, but I don't like it
    //useAnObject(b);
    }

    When I compile this, I get the following errors (gcc 4.0.1):
    c++ unaryminus.cpp -o unaryminus
    unaryminus.cpp: In function 'int main(int, char**)':
    unaryminus.cpp:39: error: invalid initialization of non-const reference
    of type 'Object&' from a temporary of type 'const Object'
    unaryminus.cpp:31: error: in passing argument 1 of 'void
    useAnObject(Object&)'

    I have tried various combinations of returning void, returning const
    Object, returning non-const Object, returning reference to Object, etc,
    but i get similar errors. Is there a way to do this?

    -Matthew
     
    Matthew Cook, Dec 20, 2006
    #1
    1. Advertising

  2. Matthew  Cook

    IR Guest

    Matthew Cook wrote:
    > I would like to overload the unary minus operator so that I can
    > negate an instance of a class and pass that instance to a function
    > without creating an explicit temporary variable. Here is an
    > example:
    >
    > #include <iostream>
    > using namespace std;
    >
    > class Object
    > {
    > public:
    > int number;
    > Object(int value);
    > const Object operator- ();


    operator -() should not modify the object, so it should be declared
    const.
    Also, are you sure you are willing to return a const Object?

    I'd rather declare it:

    Object operator -() const;


    > //friend const Object operator- (const Object& o);
    >
    > };
    >
    > Object::Object(int value) :
    > number (value)
    > {}
    >
    > const Object Object::eek:perator- ()
    > {
    > cout << "using class minus" << endl;
    > number = -number;
    > return *this;
    > }


    Object Object::eek:perator -() const
    {
    cout << "Object::eek:perator -()" << endl;
    return Object(-number);
    }

    > /*
    > const Object operator- (const Object& o)
    > {
    > cout << "using friend minus" << endl;
    > return Object(-o.number);
    > }*/
    >
    > void useAnObject(Object& o)
    > {
    > cout << "using object with number: " << o.number << endl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > Object a(4);
    > useAnObject(-a); // does not work but would like it to


    It works now :p

    > //Object b = -a; // works, but I don't like it
    > //useAnObject(b);
    > }
    >
    > When I compile this, I get the following errors (gcc 4.0.1):
    > c++ unaryminus.cpp -o unaryminus
    > unaryminus.cpp: In function 'int main(int, char**)':
    > unaryminus.cpp:39: error: invalid initialization of non-const
    > reference of type 'Object&' from a temporary of type 'const
    > Object' unaryminus.cpp:31: error: in passing argument 1 of 'void
    > useAnObject(Object&)'


    The compiler said it: your operator -() returned a const Object,
    while useAnObject expected an Object&. How could the compiler cast
    the const away?


    Cheers,
    --
    IR
     
    IR, Dec 20, 2006
    #2
    1. Advertising

  3. Matthew  Cook

    Ian Collins Guest

    Matthew Cook wrote:
    >
    > void useAnObject(Object& o)
    > {
    > cout << "using object with number: " << o.number << endl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > Object a(4);
    > useAnObject(-a); // does not work but would like it to
    > //Object b = -a; // works, but I don't like it
    > //useAnObject(b);
    > }
    >
    > When I compile this, I get the following errors (gcc 4.0.1):
    > c++ unaryminus.cpp -o unaryminus
    > unaryminus.cpp: In function 'int main(int, char**)':
    > unaryminus.cpp:39: error: invalid initialization of non-const reference
    > of type 'Object&' from a temporary of type 'const Object'
    > unaryminus.cpp:31: error: in passing argument 1 of 'void
    > useAnObject(Object&)'
    >
    > I have tried various combinations of returning void, returning const
    > Object, returning non-const Object, returning reference to Object, etc,
    > but i get similar errors. Is there a way to do this?
    >

    The compiler is telling you that you can't bind a temporary object to a
    non const reference. You are also attempting to assign a cost reference
    to a reference.

    void useAnObject( const Object& o)

    will see you right.

    --
    Ian Collins.
     
    Ian Collins, Dec 20, 2006
    #3
  4. Matthew Cook wrote:
    > I would like to overload the unary minus operator so that I can negate
    > an instance of a class and pass that instance to a function without
    > creating an explicit temporary variable. Here is an example:
    >
    > #include <iostream>
    > using namespace std;
    >
    > class Object
    > {
    > public:
    > int number;
    > Object(int value);
    > const Object operator- ();


    Why are you returning a "const Object" ? You may as well return an Object.

    I also suspect that "- OBJ" should not change OBJ. So operator- should
    be a const function.

    i.e.
    Object operator- () const;

    > //friend const Object operator- (const Object& o);
    >
    > };
    >
    > Object::Object(int value) :
    > number (value)
    > {}
    >
    > const Object Object::eek:perator- ()

    Object operator- () const
    > {
    > cout << "using class minus" << endl;
    > number = -number;

    Can't be messing with number.

    > return *this;

    Return a different Object.

    return Object( -number );

    > }
    > /*
    > const Object operator- (const Object& o)
    > {
    > cout << "using friend minus" << endl;
    > return Object(-o.number);
    > }*/
    >
    > void useAnObject(Object& o)


    If you want to accept references to temporaries as arguments, you must
    make them "const" temporaries.

    void useAnObject(const Object& o)


    > {
    > cout << "using object with number: " << o.number << endl;
    > }
    >
    > int main(int argc, char* argv[])
    > {
    > Object a(4);
    > useAnObject(-a); // does not work but would like it to
    > //Object b = -a; // works, but I don't like it
    > //useAnObject(b);
    > }
    >
    > When I compile this, I get the following errors (gcc 4.0.1):
    > c++ unaryminus.cpp -o unaryminus
    > unaryminus.cpp: In function 'int main(int, char**)':
    > unaryminus.cpp:39: error: invalid initialization of non-const reference
    > of type 'Object&' from a temporary of type 'const Object'
    > unaryminus.cpp:31: error: in passing argument 1 of 'void
    > useAnObject(Object&)'
    >
    > I have tried various combinations of returning void, returning const
    > Object, returning non-const Object, returning reference to Object, etc,
    > but i get similar errors. Is there a way to do this?


    #include <iostream>
    using namespace std;

    class Object
    {
    public:
    int number;
    Object(int value);
    Object operator- () const;
    //friend const Object operator- (const Object& o);

    };

    Object::Object(int value) :
    number (value)
    {}

    Object Object::eek:perator- () const
    {
    cout << "using class minus" << endl;
    return Object( -number );
    }
    /*
    const Object operator- (const Object& o)
    {
    cout << "using friend minus" << endl;
    return Object(-o.number);
    }*/

    void useAnObject(const Object& o)
    {
    cout << "using object with number: " << o.number << endl;
    }

    int main(int argc, char* argv[])
    {
    Object a(4);
    useAnObject(-a); // does not work but would like it to
    //Object b = -a; // works, but I don't like it
    //useAnObject(b);
    }


    >
    > -Matthew
    >
     
    Gianni Mariani, Dec 20, 2006
    #4
  5. Matthew  Cook

    IR Guest

    Ian Collins wrote:
    > The compiler is telling you that you can't bind a temporary object
    > to a non const reference.


    Damn, I missed this one... and VC8 didn't even blink on it :-/


    Cheers,
    --
    IR
     
    IR, Dec 20, 2006
    #5
  6. Matthew  Cook

    Matthew Cook Guest

    Thanks to everyone for the quick reply.

    I was returning const Objects on the advice of Effective C++'s Item 3
    (top of pg 13, possibly over-liberally applied in this case).

    I guess what I was really trying for was a function to negate the
    object in place rather than making a copy. However the more I look at
    things, the less this seems to fit with the expected behavior of
    overloading this operator. I think an explicit negate function might
    be more appropriate.

    For those who may find their way across this post in the future, IR's
    raises a good point in the prev post. This seem to only work when the
    temporary object created is passed as constant regardless of the return
    type of the operator-. It seems to be the case that implicit temporary
    variables like this are always const (perhaps someone can quote chapter
    and verse from the standard.) However, I was sure I'd done this on
    VC++ in the past. It appears the case may have changed. Google
    provides this tidbit from microsoft:

    http://msdn2.microsoft.com/en-US/library/cfbk5ddc(vs.80).aspx

    Many Thanks,
    -Matthew
     
    Matthew Cook, Dec 20, 2006
    #6
  7. Matthew  Cook

    IR Guest

    Matthew Cook wrote:
    > For those who may find their way across this post in the future,
    > IR's raises a good point in the prev post.


    I did not raise that issue. Ian Collins and Gianni Mariani did. I
    was only a victim of both my compiler and my thoughtlessness. ;-)

    > This seem to only work
    > when the temporary object created is passed as constant regardless
    > of the return type of the operator-. It seems to be the case that
    > implicit temporary variables like this are always const (perhaps
    > someone can quote chapter and verse from the standard.) However,
    > I was sure I'd done this on VC++ in the past. It appears the case
    > may have changed. Google provides this tidbit from microsoft:
    >
    > http://msdn2.microsoft.com/en-US/library/cfbk5ddc(vs.80).aspx


    Although I can't quote the relevant paragraph from the standard, the
    link you provided is right (in theory, not in practice).

    VC8 didn't generate an error (as it should, to my understanding)
    either with the code I posted earlier, nor with the following code:

    class C {};
    void f(C & c) {}

    int main()
    {
    f(C());
    }

    (of course, Comeau correctly identifies the error)


    FWIW, I figured out that VC8 generates this error only when M$
    language "extensions" are disabled. Otherwise, it only issues a
    warning when at maximum warning level (4).

    What got me wrong is that I always keep those extensions enabled
    (because when disabled, Windows headers simply don't compile), and
    that my test project wasn't at warning level 4 contrary to my habit.

    I guess this will teach me to *always* double-check that my compiler
    options are the strictest possible... :)


    Cheers,
    --
    IR
     
    IR, Dec 20, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andrew Ward
    Replies:
    6
    Views:
    687
    Ron Natalie
    Sep 26, 2003
  2. Marc

    Semantics of unary minus

    Marc, Feb 12, 2006, in forum: C Programming
    Replies:
    13
    Views:
    497
  3. SpOiLeR
    Replies:
    10
    Views:
    811
    SpOiLeR
    Oct 19, 2005
  4. Sam Stephenson
    Replies:
    9
    Views:
    233
    Caleb Clausen
    Nov 7, 2005
  5. Todd Burch
    Replies:
    3
    Views:
    156
    Jonas Roberto de Goes Filho (sysdebug)
    Aug 27, 2007
Loading...

Share This Page