Operator- overloading (same parameters, different return type) - c++

How do I overload the minus operator accepting the same number of parameters, but having different return types?
Template class:
template <typename T>
T minus (T x, T y) {
return (x - y);
}
template <typename T>
double absMinus (T x, T y) {
double sd = abs(x - y);
return sd;
}
Operator overloading class:
Minus operator-(Minus &p, Minus &q) {
return (p.something - q.something);
}
double operator-(Minus &p, Minus &q) {
return (p.something() - q.something());
}
When I tried to compile, it gave me the following error:
Minus.h:25: error: new declaration ‘double operator-(Minus&, Minus&)’
Minus.h:24: error: ambiguates old declaration ‘Minus operator-(Minus&, Minus&)’

No, you can't. Overloading can be done only when the parameter list is different. For example:
int myFun(int);
double myFun(int);
Now you are calling myFun(10). Compiler has no way to determine which version to call.

You cannot, overload resolution chooses an overload based only on the types of function parameters.

Operator overloading is just an extension of function/method overloading. For function overloading, the signature of the functions should be different. As reported in your post, the signatures of the two functions are the same.
Please note that function/method signature doesn't include the return type.
Read this for more on this topic here: Java - why no return type based method overloading?

Related

Restrictions on types sent to a function

I don't understand what restrictions apply to types that are passed to the function.
template <class T>
T sum( const T &a, const T &b) {
return a+b;
}
In this case, the types need to have the + operator defined either implicitly or overridden (eg: an int type or overridden for a class/struct/etc). As long as the + operation can be applied to the parameters, there are no restrictions.
The return type T will also need a constructor that accepts the result of the + operation

function templates and operation

I was going through a textbook and found a question regarding templates.
Q. Rewrite this function using templates to work with any type.
List the operations that any type using this template function must support
int FindLargest(const int& a, const int& b) {
int ret;
if (a > b) {
ret = a;
}
else {
ret = b;
}
return ret;
}
My answer:
template<typename T>
T FindLargest(const T& a, const T& b) {
T ret;
if (a > b) {
ret = a;
}
else {
ret = b;
}
return ret;
}
It was easy to answer first part(rewrite using template..) but I am confused with the second sentence of the question. what is it trying to say?
List the operations that any type using this template function must support
This part of the question is asking for what generic programming people call type constraint or concept.
Let's take a look at this line:
if (a > b) {
This line is comparing a and b using operator >. That means type T must support the > comparison. Otherwise, the code does not compile.
As a quick experiment, you may try to declare an empty class and instantiate the function template with it.
class Empty {};
int main() {
Empty x, y;
FindLargest(x, y);
}
The compiler may emits an error message like:
error: no match for 'operator>' (operand types are 'const Empty' and 'const Empty')
So, one of several items in your list should be the larger-than comparison operation using >. Also note that this function template also requires other operations. I will leave it to you to find out.
2) is asking you which things the type T needs to be able to do for the template to compile and operate correctly...
Consider:
T ret;
For the above to work, T must have a default constructor.
if (a > b) {
For the above to work, there must be some > operator that can - directly or indirectly - compare two instances of the type, returning something that either is of boolean type, or can be converted thereto. The two most obvious examples of direct support would be either an bool T::operator>(const T& rhs) const member function or a stand-alone bool operator>(const T& lhs, const T& rhs) function. An example of indirect support is an T::operatorsometype() const conversion operator to a type - such as double - that itself can be compared with >.
ret = a;
For the above to work, there needs to be a (copy / non-move) assignment operator.
Continue this style of analysis to fully answer the question.

How to define member class operator based on the class parameters

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()
);
}

Numeric Array Class: Multiplication using friend functions

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

Function Composition Operator

As a small exercise in functional programming in C++, I want to overload the operator* to allow me to compose 2 functions.
What stumps me is that if I define my operator like this:
std::function<float(float)> operator*(std::function<float(float)> func1, std::function<float(float)> func2)
{
// ...
}
I cannot use it with regular functions as in:
float f(float);
float g(float);
auto composite = f*g;
Because I get:
error: invalid operands of types ‘float(float)’ and ‘float(float)’ to binary ‘operator*’
If I try to add a function pointer only version as in:
std::function<float(float)> operator*(float(*func1)(float) , float(*func2)(float))
{
return [func1, func2](float x) { return func1(func2(x)); };
}
I get this error:
error: ‘std::function<float(float)> operator*(float (*)(float), float (*)(float))’ must have an argument of class or enumerated type
I was able to get it to work by adding a make_function helper, but that really makes the code ugly.
Is there a way to get this operator to automatically cast functions to std::function instances?
Unfortunately, C++ does not allow operators to be overloaded for built-in types. Just as you cannot implement your own operator* for two ints, you cannot implement it for two function pointers, except if you represent these functions with the std::function type which is a class and therefore not a built-in type.
You can, however, instead of using an operator, simply use a function:
std::function<float(float)> dot(float(*func1)(float) , float(*func2)(float))
{
return [func1, func2](float x) { return func1(func2(x)); };
}