friend function overloading

B

barbaros

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;
};
 
V

Victor Bazarov

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
 
B

barbaros

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
 
V

Victor Bazarov

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
 
B

barbaros

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;
}
 
M

Marc

barbaros said:
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.
 
Ö

Öö Tiib

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;

}

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;
}
 
V

Victor Bazarov

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
 
J

James Kanze

And I hope the compiler is capable of optimizing this to

b(i) *= a;
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.)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top