friend function overloading

Discussion in 'C++' started by barbaros, Oct 20, 2010.

  1. barbaros

    barbaros Guest

    Hi everybody,

    I cannot understand why in the code included below the operator *
    cannot be overloaded, once as a method then as a friend function. The
    code compiles well, but when I uncomment the line "numeric
    &operator*(const vector &b) const;" I get the following errors at line
    15 (where the second, overloaded, operator is declared): "error:
    declaration of 'operator*' as non-function" and "error: expected ';'
    before '<' token".

    My compiler is gcc version 4.3.3 (Debian 4.3.3-3).

    What am I doing wrong ?

    Thank you very much, Cristian Barbarosie
    ----------------------------------------------------
    // VECTOR CLASS DECLARATION
    template<typename numeric> class vector;

    // DECLARATION OF FRIEND FUNCTIONS
    template<typename numeric> int get_dim(const vector<numeric> &b);
    template<typename numeric> vector<numeric> &operator*(numeric a, const
    vector<numeric> &b);

    // VECTOR CLASS DEFINITION
    template<typename numeric> class vector {
    public:
    vector(int n);
    numeric &operator()(int i) const;
    // numeric &operator*(const vector &b) const;
    friend int get_dim<numeric>(const vector<numeric> &b);
    friend vector<numeric> &operator*<numeric>(numeric a, const
    vector<numeric> &b);
    private:
    int size;
    numeric *elements;
    };
     
    barbaros, Oct 20, 2010
    #1
    1. Advertising

  2. On 10/20/2010 9:16 AM, Pete Becker wrote:
    > On 2010-10-20 09:00:58 -0400, barbaros said:
    >
    >> // VECTOR CLASS DEFINITION
    >> template<typename numeric> class vector {
    >> public:
    >> vector(int n);
    >> numeric &operator()(int i) const;
    >> // numeric &operator*(const vector &b) const;

    >
    > vector is a template. Change it to vector<numeric>.


    Inside 'vector' template definition 'vector' is the same as
    'vector<numeric>', isn't it? Why should it be spelled out? It's gotta
    be a buggy compiler if it requires the template arguments there.

    This should compile just fine:

    template<typename numeric> class vector {
    public:
    vector(int n);
    numeric &operator*(const vector &b) const;
    private:
    int size;
    numeric *elements;
    };

    int main()
    {
    vector<double> vd1(5), vd2(5);
    vd1(42);
    vd1 * vd2;
    }

    Now, I don't think the friend declarations are valid in the original
    post. At least Comeau chokes on them. It only allows declaring, for
    instance, the operator* if the name is qualified:

    friend vector<numeric>& ::eek:perator* <numeric> ...

    Now, why are those things all return references to non-const objects?
    They should return objects.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Oct 20, 2010
    #2
    1. Advertising

  3. barbaros

    barbaros Guest

    On Oct 20, 3:23 pm, Victor Bazarov <> wrote:

    > This should compile just fine:
    >
    >    template<typename numeric> class vector {
    >    public:
    >      vector(int n);
    >      numeric &operator*(const vector &b) const;
    >    private:
    >      int size;
    >      numeric *elements;
    >    };
    >
    >    int main()
    >    {
    >      vector<double> vd1(5), vd2(5);
    >      vd1(42);
    >      vd1 * vd2;
    >    }
    >
    > Now, I don't think the friend declarations are valid in the original
    > post.  At least Comeau chokes on them.  It only allows declaring, for
    > instance, the operator* if the name is qualified:
    >
    >      friend vector<numeric>& ::eek:perator* <numeric> ...
    >
    > Now, why are those things all return references to non-const objects?
    > They should return objects.


    Because I am trying to avoid unnecessary copy operations.
    My vectors are quite large.
    Of course you are right, the methods should return references to const
    objects.

    Thank you.
    Cristian Barbarosie
     
    barbaros, Oct 22, 2010
    #3
  4. On 10/22/2010 10:29 AM, barbaros wrote:
    > On Oct 20, 3:23 pm, Victor Bazarov<> wrote:
    >
    >> This should compile just fine:
    >>
    >> template<typename numeric> class vector {
    >> public:
    >> vector(int n);
    >> numeric&operator*(const vector&b) const;
    >> private:
    >> int size;
    >> numeric *elements;
    >> };
    >>
    >> int main()
    >> {
    >> vector<double> vd1(5), vd2(5);
    >> vd1(42);
    >> vd1 * vd2;
    >> }
    >>
    >> Now, I don't think the friend declarations are valid in the original
    >> post. At least Comeau chokes on them. It only allows declaring, for
    >> instance, the operator* if the name is qualified:
    >>
    >> friend vector<numeric>& ::eek:perator*<numeric> ...
    >>
    >> Now, why are those things all return references to non-const objects?
    >> They should return objects.

    >
    > Because I am trying to avoid unnecessary copy operations.
    > My vectors are quite large.
    > Of course you are right, the methods should return references to const
    > objects.


    I understand the desire to avoid copying. But what about the semantics
    of your operations? What object do you return by a reference when you
    *have to* create a new one (like when multiplying two vectors)? It's
    not like you can return the left operand or the right operand, anyway.
    You need to rely on the compiler's ability to optimize the copying.
    Read up on "return value optimization" and "named return value
    optimization".

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Oct 22, 2010
    #4
  5. barbaros

    barbaros Guest

    On Oct 22, 3:57 pm, Victor Bazarov <> wrote:
    > I understand the desire to avoid copying. But what about the semantics
    > of your operations? What object do you return by a reference when you
    > *have to* create a new one (like when multiplying two vectors)? It's
    > not like you can return the left operand or the right operand, anyway.
    > You need to rely on the compiler's ability to optimize the copying.
    > Read up on "return value optimization" and "named return value
    > optimization".


    I confess I do not understand your objections. Of course I have to
    create
    a new object inside the operator* (see the piece of code below).
    But suppose the operator* returned an object A instead of a const
    reference.
    Then a second object B will be created in the main program, and the
    returned
    temporary object A will be copied onto B. This is what I am trying to
    avoid.

    template<typename numeric>
    const vector<numeric> &operator*(numeric a, const vector<numeric> &b)
    {
    vector<numeric> *prod = new vector<numeric>(get_dim(b));
    for (int i = 1; i <= get_dim(b); ++i)
    (*prod)(i) = a*b(i);
    return *prod;
    }
     
    barbaros, Oct 26, 2010
    #5
  6. barbaros

    Marc Guest

    barbaros wrote:

    > I confess I do not understand your objections. Of course I have to create
    > a new object inside the operator* (see the piece of code below).


    Ah, you are using "new". The natural fear was that you might return a
    reference to a temporary. This means that you will need to handle the
    deletion yourself in the caller, not very convenient.

    > But suppose the operator* returned an object A instead of a const
    > reference. Then a second object B will be created in the main
    > program, and the returned temporary object A will be copied onto B.
    > This is what I am trying to avoid.


    And that is something compilers have become good at avoiding too, with
    the blessing of the standard (read up on copy elision and (named) return
    value optimization).

    > template<typename numeric>
    > const vector<numeric> &operator*(numeric a, const vector<numeric> &b)
    > {
    > vector<numeric> *prod = new vector<numeric>(get_dim(b));
    > for (int i = 1; i <= get_dim(b); ++i)
    > (*prod)(i) = a*b(i);
    > return *prod;
    > }


    I would use a boost::transform_iterator to avoid this 2-step
    initialization, but I guess it doesn't really matter if numeric is a
    cheap builtin type.
     
    Marc, Oct 26, 2010
    #6
  7. barbaros

    Öö Tiib Guest

    On Oct 26, 2:16 pm, barbaros <> wrote:
    > On Oct 22, 3:57 pm, Victor Bazarov <> wrote:
    >
    > > I understand the desire to avoid copying.  But what about the semantics
    > > of your operations?  What object do you return by a reference when you
    > > *have to* create a new one (like when multiplying two vectors)?  It's
    > > not like you can return the left operand or the right operand, anyway.
    > > You need to rely on the compiler's ability to optimize the copying.
    > > Read up on "return value optimization" and "named return value
    > > optimization".

    >
    > I confess I do not understand your objections. Of course I have to
    > create
    > a new object inside the operator* (see the piece of code below).


    By that code the result of your operator*(numeric,vector<numeric>)
    just leaks?

    > But suppose the operator* returned an object A instead of a const
    > reference.
    > Then a second object B will be created in the main program, and the
    > returned
    > temporary object A will be copied onto B. This is what I am trying to
    > avoid.
    >
    > template<typename numeric>
    > const vector<numeric> &operator*(numeric a, const vector<numeric> &b)
    > {
    >   vector<numeric> *prod = new vector<numeric>(get_dim(b));
    >   for (int i = 1; i <= get_dim(b); ++i)
    >     (*prod)(i) = a*b(i);
    >   return *prod;
    >
    > }


    I think Victor asked why you do not do it simply?:

    template<typename numeric>
    vector<numeric> operator*( numeric a, vector<numeric> b )
    {
    for ( int i = 1; i <= get_dim( b ); ++i )
    b( i ) = a*b( i );
    return b;
    }
     
    Öö Tiib, Oct 26, 2010
    #7
  8. On 10/26/2010 10:19 AM, Öö Tiib wrote:
    > On Oct 26, 2:16 pm, barbaros<> wrote:
    >> On Oct 22, 3:57 pm, Victor Bazarov<> wrote:
    >>
    >>> I understand the desire to avoid copying. But what about the semantics
    >>> of your operations? What object do you return by a reference when you
    >>> *have to* create a new one (like when multiplying two vectors)? It's
    >>> not like you can return the left operand or the right operand, anyway.
    >>> You need to rely on the compiler's ability to optimize the copying.
    >>> Read up on "return value optimization" and "named return value
    >>> optimization".

    >>
    >> I confess I do not understand your objections. Of course I have to
    >> create
    >> a new object inside the operator* (see the piece of code below).

    >
    > By that code the result of your operator*(numeric,vector<numeric>)
    > just leaks?
    >
    >> But suppose the operator* returned an object A instead of a const
    >> reference.
    >> Then a second object B will be created in the main program, and the
    >> returned
    >> temporary object A will be copied onto B. This is what I am trying to
    >> avoid.
    >>
    >> template<typename numeric>
    >> const vector<numeric> &operator*(numeric a, const vector<numeric> &b)
    >> {
    >> vector<numeric> *prod = new vector<numeric>(get_dim(b));
    >> for (int i = 1; i<= get_dim(b); ++i)
    >> (*prod)(i) = a*b(i);
    >> return *prod;
    >>
    >> }

    >
    > I think Victor asked why you do not do it simply?:
    >
    > template<typename numeric>
    > vector<numeric> operator*( numeric a, vector<numeric> b )
    > {
    > for ( int i = 1; i<= get_dim( b ); ++i )
    > b( i ) = a*b( i );


    And I hope the compiler is capable of optimizing this to

    b(i) *= a;

    ....

    > return b;
    > }


    The alternative is

    ...operator* (N a, const vector<N>& b)
    {
    vector<N> retval(b);
    // same cycle just with 'retval;
    return retval;
    }

    , and rely on the compiler to do the return value optimization (without
    unnecessary copying).

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Oct 26, 2010
    #8
  9. barbaros

    James Kanze Guest

    On Oct 26, 5:10 pm, Victor Bazarov <> wrote:
    > On 10/26/2010 10:19 AM, Öö Tiib wrote:
    > > On Oct 26, 2:16 pm, barbaros<> wrote:
    > >> On Oct 22, 3:57 pm, Victor Bazarov<> wrote:


    > >>> I understand the desire to avoid copying. But what about the semantics
    > >>> of your operations? What object do you return by a reference when you
    > >>> *have to* create a new one (like when multiplying two vectors)? It's
    > >>> not like you can return the left operand or the right operand, anyway..
    > >>> You need to rely on the compiler's ability to optimize the copying.
    > >>> Read up on "return value optimization" and "named return value
    > >>> optimization".


    > >> I confess I do not understand your objections. Of course
    > >> I have to create a new object inside the operator* (see the
    > >> piece of code below).


    > > By that code the result of your operator*(numeric,vector<numeric>)
    > > just leaks?


    > >> But suppose the operator* returned an object A instead of
    > >> a const reference. Then a second object B will be created
    > >> in the main program, and the returned temporary object
    > >> A will be copied onto B. This is what I am trying to avoid.


    > >> template<typename numeric>
    > >> const vector<numeric> &operator*(numeric a, const vector<numeric> &b)
    > >> {
    > >> vector<numeric> *prod = new vector<numeric>(get_dim(b));
    > >> for (int i = 1; i<= get_dim(b); ++i)
    > >> (*prod)(i) = a*b(i);
    > >> return *prod;
    > >> }


    > > I think Victor asked why you do not do it simply?:


    > > template<typename numeric>
    > > vector<numeric> operator*( numeric a, vector<numeric> b )
    > > {
    > > for ( int i = 1; i<= get_dim( b ); ++i )
    > > b( i ) = a*b( i );


    > And I hope the compiler is capable of optimizing this to
    >
    > b(i) *= a;


    > ...


    > > return b;
    > > }


    > The alternative is


    > ...operator* (N a, const vector<N>& b)
    > {
    > vector<N> retval(b);
    > // same cycle just with 'retval;
    > return retval;
    > }


    > , and rely on the compiler to do the return value optimization
    > (without unnecessary copying).


    This will probably result in the least copies for a naïve
    implementation. The standard solution here is some sort of
    template expressions, so that the actual values will only be
    calculated when the final target is known (in the constructor or
    the assignment operator). (Before templates, the same thing was
    done using virtual functions -- since the actual instances of
    the derived classes were all temporaries, the compiler knew the
    dynamic type, and could still inline the virtual functions.)

    --
    James Kanze
     
    James Kanze, Oct 27, 2010
    #9
    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. Iyer, Prasad C

    Overloading __init__ & Function overloading

    Iyer, Prasad C, Sep 30, 2005, in forum: Python
    Replies:
    3
    Views:
    6,413
    Fredrik Lundh
    Sep 30, 2005
  2. Fredrik Lundh
    Replies:
    0
    Views:
    451
    Fredrik Lundh
    Sep 30, 2005
  3. Steve Holden
    Replies:
    0
    Views:
    432
    Steve Holden
    Sep 30, 2005
  4. Iyer, Prasad C
    Replies:
    4
    Views:
    581
    John J. Lee
    Sep 30, 2005
  5. Peter
    Replies:
    2
    Views:
    278
    Öö Tiib
    Jun 6, 2013
Loading...

Share This Page