I have been trying to solve this bug for days. I made a generic array class, from which I used generic inheritance to create a numeric array. Everything works perfect; however, I am having trouble with multiplication/scaling of the numeric array. I overloaded the operator* in the following standard way:
//Scaling operator
template <typename Type>
NumericArray<Type>& NumericArray<Type> :: operator * (const double factor) // scaling the elements
{
for (int i = 0; i < (*this).size(); i++)
{
(*this)[i] *= factor;
}
return *this;
}
Of course, due to the inherent order demanded by this implementation, I can only do multiplication in the way of array * 2. But I also want to be able to write 2 * array. So I decided to implement a friend function as follows:
template <typename Type>
NumericArray<Type> operator* (Type factor, const NumericArray<Type>& num_array)
{
return(num_array * factor);
}
The declaration of this friend function is as follows:
template <typename Type> friend NumericArray<Type> operator * (double factor, const NumericArray<Type>& num_array);
But when I try to write 2 * array in main(), I get the error message:
Severity Code Description Project File Line
Error C2678 binary '*': no operator found which takes a left-hand operand of type 'const NumericArray' (or there is no acceptable conversion)
The error makes me think that main() doesn't even recognize that the friend function exists. I have used friend functions a few times before, but I am pretty new to templates. I've been told that templates and generic programming in general has some weird quirky necessities, which may cause unforeseen circumstances.
For anyone who wants to see the full program, see the dropbox link:
https://www.dropbox.com/sh/86c5o702vkjyrwx/AAB-Pnpl_jPR_GT4qiPYb8LTa?dl=0
Thanks again for your help:)
NumericArray<Type> in the friend function is const, it can not call a not const function--- NumericArray<Type>& NumericArray<Type> :: operator * (const double factor)
NumericArray<Type>& operator * (const double factor)
This is a non const member function. This means it may mutate the object it's called on.
Your parameter in the free operator function (which doesn't need to be a friend if calling the public operator above) is
const NumericArray<Type>&
and therefore const qualified.
To solve it, you need to change the member function to be callable on const qualified instances (given that it really does not mutate it's instance, which it shouldn't)(*):
NumericArray<Type>& operator * (const double factor) const
(*) Yours is mutating it's instance, this is counter intuitive:
c = a * b;
You don't want a to be changed after that, in general.
As Nicky C suggests in his answer, the best approach here is probably to have an operator*= as (non const, public) member function, which is doing what currently your operator* seems to be doing.
Then you add two free operator* functions which use the operator*= to implement their behaviour.
So no need for friends in this case.
I am not sure whether I want to explain everything since it can be complicated if we go deep. But in short:
You've mixed up the meanings and implementations of *= and *.
The errors involve a lot of things: template instantiation, const-correctness, overload resolution...
So, let's just look at the idiomatic way to do so.
Step 1: Write a member operator *=.
template <typename Type>
class NumericArray
{
//...
NumericArray& operator *= (const Type factor)
{
[[ Code that scales up every element, i.e. your for-loop ]]
return *this;
}
//...
}
Step 2: Write a pair of non-member non-friend operator *
template <typename Type>
NumericArray<Type> operator * (const NumericArray<Type>& num_array, const Type factor)
{
NumericArray<Type> new_num_array = num_array; // Copy construct
new_num_array *= factor; // Scale up
return new_num_array;
}
// And similarly for factor*num_array
Related
Why is it giving the error.
class Complex{
int real,imaginary;
public:
Complex():real(0),imaginary(0){};
Complex(int real, int imaginary):real(real),imaginary(imaginary){};
int getreal()const{return real;}
int getimaginary()const{return imaginary;};
Complex &operator=(const Complex& );
Complex operator*(){
return Complex(real,-imaginary);
}
Complex operator+(const Complex &a, const Complex &d){
return Complex (d.getreal()+a.getreal(),a.getimaginary()+d.getimaginary());
}
};
When trying to overload the assingment operator.
Eroor says: too many parameter
What operators can we overload as member function and what not
When overriding operators that have left and right parameters, you should just pass the right parameter and declare it like this:
Complex operator+(const Complex &d){
return Complex(d.getreal() + getreal(), getimaginary() + d.getimaginary());
}
When doing that, when you call getreal() or directly access that variable without specifing the parameter, it will use the left parameter of the operator.
Some of the operators that cannot be overloaded are scope (::), ternary (:), sizeof, member access (.) and some others.
When defining an overloaded operator as a member function, the object pointed at by the this pointer is implicitly the first argument. So your operator overload needs to look like:
class Complex {
// ...
Complex operator+(const Complex &d) const {
return Complex (real + d.real, imaginary + d.imaginary);
}
};
Note that you don't need the getter functions, since you already have access to the data members inside the class.
Outside the class, i.e. as a non-member function, your overloaded operator is perfectly fine.
Is it possible to define different = operators for different template arguments. Let's assume that I want to use different methods for converting arguments of different types:
template <class T,class U>
class cTest
{
private:
public:
T x;
U y;
//typical case
cTest<T,U>& operator =(const cTest<T,U> &that)
{
return *this;
}
//operator = based on the LHS type 1
cTest<uint16_t,U>& operator =(const cTest<int,U> &that)
{
cout<<"cTest<uint16_t,U>& operator =(const cTest<int,U> &that)"<<endl;
return cTest<uint16_t,U>();
}
//operator = based on the LHS type 2
cTest<uint8_t,U>& operator =(const cTest<int,U> &that)
{
cout<<"cTest<uint8_t,U>& operator =(const cTest<int,U> &that)"<<endl;
return cTest<uint16_t,U>();
}
};
You are trying to overload operators/functions by return type. This is not allowed by the C++ standard:
13.1/2: Certain function declarations cannot be overloaded: — Function declarations that differ only in the return type cannot be
overloaded.
Possible workarounds:
You could consider using a function instead on an operator, passing by reference a variable for storing the return value. In this case the overload would be possible. But it's less handy than the assignment operator, and I guess that's no what you were looking for.
A better approach would be to add a separate conversion operator between cTest<uint16_t,U> and cTest<uint8_t,U>.
I suggest that you have a look at Template Metaprogramming.
Template Metaprogramming is a generic programming technique that uses extremely early binding. The compiler acts as an interpreter or a "virtual computer" that emits the instructions that make up the final program. It can be used for static configuration, adaptive programs, optimization and much more.
You can basically let the compiler decide what template definition to use, depending on the respective values. An example for a quaternion multiplication would look like:
template <typename Quaternion>
typename std::enable_if_t<sds::is_quaternion<Quaternion>::value, Quaternion>
operator+(const Quaternion &a, const Quaternion &b)
{
return Quaternion
(
a.u() + b.u(),
a.v() + b.v()
);
}
I've read the section 13.5 of the working draft N3797 and I've one question. Let complex be a class type which represents complex numbers. We can define the following operator function:
complex operator+(double d, complex c)
{
return *new complex(d+c.get_real(),c.get_imagine());
}
But how this operator function can be implements as a complex member function? Or must I to declare this operator function in every module which I've intend to use them?
There are two ways to define a binary operator overload, such as the binary + operator, between two types.
As a member function.
When you define it as member function, the LHS of the operator is an instance of the class. The RHS of the operator is the argument to the function. That's why when you define it as member function, it can only have one argument.
As a free function.
These functions must have two arguments. The first argument is the LHS of the operator and the second argument is the RHS of the operator.
Since double is not a class, you have to define operator+ overload between double as LHS and complex as RHS as a free function, with double const& or double as the first argument type and complex const& or complex as the second argument type.
What you're looking for is this:
inline complex operator +(double d, const complex& c)
{
return complex(d+c.get_real(), c.get_imagine());
}
This cannot be a member function if you want the operator to handle a left-side of the operator as a double. It must be a free function, possibly friended if access to anything besides the public interface of complex is needed.
If you want the right side of the add-op to be a double, a member function can be crafted:
complex operator +(double d) const
{
return complex(d+get_real(), get_imagine());
}
Note this is assuming this definition is within the body of the complex class definition. But in the interest of clarity I would recommend both be inline free functions.
Implicit Construction
Lined up with the usual suspects, what you're at-least-appearing to try to do is generally done with an implicit conversion constructor and a general free-function. By providing this:
complex(double d) : real(d), imagine()
{
}
in the class definition a double can implicitly construct a temporary complex where needed. This allows this:
inline complex operator +(const complex& lhs, const complex& rhs)
{
return complex(lhs.get_real() + rhs.get_real(),
lhs.get_imagine() + rhs.get_imagine());
}
to be used as a general solution to all sensible manifestations of what you appear to want.
In C++, operator overloading requires class types. You cannot overload the + operator for the basic type double.
Also, except in certain circumstances (short-lived programs or throwaway code), the pointer resulting from a call to the new operator should be captured, so that it can be later released with delete, preventing a situation known as a memory leak.
For it to be a member, the first parameter must be of the class type(though it is not explicitly specified). But you are sending a double as first argument. If you need this to work either make it friend function or just non-member function which can work only using public interface of the Complex class. And as others pointed out, you are leaking memory.
I want to overload the * operator for a class, one which is in case it is multiplied by a real number double and the other is when multiplied by the same class type.
Below is my code:
class Vector2D {
...
friend Vector2D operator* (const Vector2D&);
friend Vector2D operator* (const double); // getting error here
};
The error I'm getting is: 'Vector2D operator*(double)' must have an argument of class or enumerated type
Is it possible to overload operators more than once, and if so, why am I getting an error?
class Vector2D {
...
friend Vector2D operator* (const Vector2D&);
That is overloading unary operator* (i.e. dereference operator) as a free function, not overloading the multiplication of two vectors. You cannot overload operators that apply only to non-class types, and that is the error for:
friend Vector2D operator* (const double);
You probably meant to write:
friend Vector2D operator*(const Vector2D&,const Vector2D&);
friend Vector2D operator*(const Vector2D&,double);
The problem is that you're overloading unary operator*, not binary. Your friend declarations are not member functions.
Either remove the friend (if you want to overload the operators as member functions), or else add a first parameter of type const Vector2D& or Vector2D& (if you want to overload as free functions). The latter is usually preferable, since then you get implicit conversion on both arguments -- member operator overloads will implicitly convert the right hand side but not the left.
The reason you might not want a reference as the first argument to binary operator*, is so that you can implement it like this:
Vector2D operator*(Vector2D lhs, const Vector2D &rhs) {
lhs *= rhs;
return lhs;
}
The same would apply to addition (and addition of two vectors makes sense to me in a way that multiplication of two vectors does not).
You are not allowed to override the operators for built-in types. In this case you're providing a declaration for a unary * operator for type double which isn't allowed.
I think you want to remove the friend declaration and make these member functions instead.
I wrote an abstraction class for a math object, and defined all of the operators. While using it, I came across:
Fixed f1 = 5.0f - f3;
I have only two subtraction operators defined:
inline const Fixed operator - () const;
inline const Fixed operator - (float f) const;
I get what is wrong here - addition is swappable (1 + 2 == 2 + 1) while subtraction is not (same goes for multiplication and division).
I immediately wrote a function outside my class like this:
static inline const Fixed operator - (float f, const Fixed &fp);
But then I realized this cannot be done, because to do that I would have to touch the class's privates, which results to using the keyword friend which I loath, as well as polluting the namespace with a 'static' unnecessary function.
Moving the function inside the class definition yields this error in gcc-4.3:
error: ‘static const Fixed Fixed::operator-(float, const Fixed&)’ must be either a non-static member function or a non-member function
Doing as GCC suggested, and making it a non-static function results the following error:
error: ‘const Fixed Fixed::operator-(float, const Fixed&)’ must take either zero or one argument
Why can't I define the same operator inside the class definition? if there's no way to do it, is there anyway else not using the friend keyword?
Same question goes for division, as it suffers from the same problem.
If you need reassuring that friend functions can be OK:
http://www.gotw.ca/gotw/084.htm
Which operations need access to
internal data we would otherwise have
to grant via friendship? These should
normally be members. (There are some
rare exceptions such as operations
needing conversions on their left-hand
arguments and some like operator<<()
whose signatures don't allow the *this
reference to be their first
parameters; even these can normally be
nonfriends implemented in terms of
(possibly virtual) members, but
sometimes doing that is merely an
exercise in contortionism and they're
best and naturally expressed as
friends.)
You are in the "operations needing conversions on the left-hand arguments" camp. If you don't want a friend, and assuming you have a non-explicit float constructor for Fixed, you can implement it as:
static inline Fixed operator-(const Fixed &lhs, const Fixed &rhs) {
return lhs.minus(rhs);
}
then implement minus as a public member function, that most users won't bother with because they prefer the operator.
I assume if you have operator-(float) then you have operator+(float), so if you don't have the conversion operator, you could go with:
static inline Fixed operator-(float lhs, const Fixed &rhs) {
return (-rhs) + lhs;
// return (-rhs) -(-lhs); if no operator+...
}
Or just Fixed(lhs) - rhs if you have an explicit float constructor. Those may or may not be as efficient as your friend implementation.
Unfortunately the language is not going to bend over backwards to accommodate those who happen to loathe one of its keywords, so operators can't be static member functions and get the effects of friendship that way ;-p
"That's what friends are for..."
You could add an implicit conversion between float and your type (e.g. with a constructor accepting float)... but I do think using a friend is better.
When you define something like this,
inline const Fixed operator - (float f) const;
you are saying that I want this operator(you are inside the class) to operate on a specific type, float here for example.
Whereas a friend binary operator, means an operation between two types.
class Fixed
{
inline friend const Fixed operator-(const Fixed& first, const float& second);
};
inline const Fixed operator-(const Fixed& first, const float& second)
{
// Your definition here.
}
with friend operators you can have your class on either side of the operator it self.
In general, free function operators for arithmetic operations are better than implementing member functions. The main reason is the problem you are facing now. The compiler will treat the left and right sides differently. Note that while strict OO followers will consider only those methods inside the class curly braces part of its interface, but it has been argued by experts that not to be the case in C++.
If the free function operator requires access to private members, make the operator friend. After all if it is provided in the same header file (following Sutter's rationale above) then it is part of the class.
If you really want to avoid it and don't mind making your code less idiomatic (and thus less maintainable) you can provide a public method that does the real work and dispatch to that method from the operator.
class Fixed {
private:
Fixed();
Fixed( double d ); // implicit conversion to Fixed from double
Fixed substract( Fixed const & rhs ) const;
// ...
};
Fixed operator-( Fixed const & lhs, Fixed const & rhs )
{
return lhs.substract( rhs );
}
In the code above, you can substract Fixed - Fixed, Fixed - double, double - Fixed. The compiler will find the free function and implicitly convert (in the example through the double constructor) the doubles into Fixed objects.
While this is unidiomatic for arithmetic operators, it is close to the idiomatic way of proving a polymorphic dump operator. So while not being the most natural solution it won't be the most surprising code around either
// idiomatic polymorphic dump operator
class Base {
public:
virtual std::ostream& dump( std::ostream & ) const;
};
std::ostream& operator<<( std::ostream& o, Base const & d )
{
return d.dump( o );
}