Operator priority with operator overload? - c++

I used operator overloading for my own Bignum header, and there are some operator priority problem.
Compiler says there is some error when I do bignum+int.
(My Bignum class name is 'bignum'. Don't mind that)
Here is my class definition:
operator long long(void) const {
return atoll(num.c_str());
}
operator +(bignum b) {
//c=this+b
return c;
}
And here is the case that error happens:
bignum a(1);
int b=1;
bignum c = a+b; //this is the case
ERRORS
line 7 : IntelliSense: "+" More than one of the operators is
consistent with the operand. Built-in operators "arithmetic +
arithmetic" Function "minary::bignum::operator+(minary::bignum
b)" The operand format is minary::bignum +
int. c:\Users\Secret\Documents\Visual Studio
2013\Projects\Calculator\Calculator\Source.cpp 11 3 Calculator
Thanks in advance.

The easiest approach is to make the conversion to integers explicit: many implicit conversions cause problems anyway. Sometimes implicit conversions are useful but if you want to deal with mixed type arithmetic they tend to be more a problem than help:
class bignum {
// ...
explicit operator long long() const { ... }
// ...
};
Making the conversion operator explicit is a C++11 feature. Your class also seems to have an implicit conversion from integral types to bignum, i.e., a corresponding constructor. Prior to C++11 you could only make these constructors explicit. This may be another option to deal with the ambiguity but it would have the effect that the conversion to long long and the built-in integer addition is used. My guess that you want a bignum as a result which requires that there is no suitable conversion to an integral type.
Note that the question has nothing to do with operator priority: for any given expression the compiler determines which overloads are the best fit (roughly: require the least amount of implicit conversions). If it finds multiple equally good candidates it considers the program to be ambiguous and asks for the ambiguity to be sorted out.

Related

Is it possible to specify return types from bitwise manipulation?

Much of the code in place at the company I work for frequently uses unsigned char types for small numbers to avoid unwanted padding in data structures. I rarely see a problem with this, however I ran into a small issue with implicit conversion while setting error flags with bitwise operators. I found a workaround by simply being explicit, but I was wondering if there was a more elegant way. Btw we compile with c++11
Given the error code enum below:
enum ErrorType : unsigned char
{
OK. = 0x00,
ERROR01 = 0x01,
ERROR02 = 0x02
};
and assuming I have some classes with private members of type errorType
which will use public members to set or unset flags, for example:
struct S
{
public:
void setError1();
void unsetError1();
private:
ErrorType errorType;
};
If I try to set values implicitly live below:
void S::setError1()
{
this->errorType |= ERROR01;
}
I get type conversion errors
however if I explicitly cast the bitwise conversion it works
this->errorType = ErrorType(this->errorType | ERROR01);
It would appear that the problem is that the output of bitwise conversions is always an integer and does not necessarily reflect the input type. Is this true? and if so is there a way to specify a type for it so I don't have to explicitly cast every time?
When no overload operator for the enums exist, the bitwise operation resort on the builtin operator version, after promoting the enums to their underlaying type, you can cast it explicitly as:
this->errorType = static_cast<ErrorType>(errorType | ERROR01);
or overload the |= operator to allow:
ErrorType& operator|=(ErrorType& lhs, ErrorType rhs) {
lhs = static_cast<ErrorType>(lhs | rhs);
return lhs;
}
void S::setError1()
{
this->errorType |= ERROR01;
}
It would appear that the problem is that the output of bitwise conversions is always an integer and does not necessarily reflect the input type. Is this true?
Since the early days of C, math operations on types smaller than int will promote the types to int.
The reasoning -- when int was "the big integer type" -- was that the promotion to int would be cheap and would prevent some overflow situations.
if so is there a way to specify a type for it so I don't have to explicitly cast every time?
Yes! Define the operation, rather than accept the default-generated implementation.
ErrorType& operator |= ( ErrorType &left, ErrorType right )
{
return left = ErrorType(left | right);
}
Yes, the result of a bitwise operation is an integral type after promotion. When two integral operands are participating in the arithmetic operation, they are first promoted to at least an int type, where the operation is performed on ints with a result being an int. There is no implicit conversion from int to enum, so you have to cast back yourself.
Here is more information on integral promotion rules: https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion

How to use a Caret "^" in C++ for Exponentiation

I am currently rewriting MATLAB code into C++ code. To have the ability to raise "a" to the power of "b" just by typing "a^b" would make my life so much easier as this is how much of the original code was written in MATLAB.
Is there a way to do this? (I am using primitive types)
I'll happily accept a solution that does NOT involve parenthesis and commas like the pow(a,b) method.
Thanks in advance.
While it is possible to overload ^ to do exponentiation, you shouldn't. It's a bad idea.
#AaronF's answer shows how ugly the code to do this is, but that's only the tip of the iceberg. The real problem comes when you try to actually use this in real code. The problems stem from one simple fact: overloading an operator changes the actions carried out by that operator, but does not affect either the precedence or associativity of that operator. In the case of ^, both the precedence and the associativity are completely wrong for exponentiation.
precedence
In C++, the ^ operator has quite low precedence. Exponentiation should have very high precedence. For example, an expression like x^y*z would normally mean xyz--but what it will mean in C++ is xyz. In fact in C++, ^ has precedence even lower than addition and subtraction, so even x^y+z comes out wrong--it means xy+z instead of the xy+z that you'd want/normally expect.
Associativity
Exponentiation is right associative--but in C++, the ^ operator is left associative. For example, given an expression like x^y^z, what you'd want/expect would be for it to mean xyz, but what you'll get is (xy)z (equivalent to xyz).
Result
These mean that if you do overload operator^ to do exponentiation, you'll only have gotten away from using the name pow. You will not get away from most of the parentheses; in any non-trivial expression, you'll still need parentheses to force the proper precedence and associativity, because as outlined above, the precedence and associativity C++ assigns to operator^ are both entirely wrong for exponentiation.
Conclusion
Although you can overload operator^ to do exponentiation, this is one of those places where discretion is the better part of valor. When you overload operators in C++, you really have three factors to take into account: the name, the precedence and the associativity. For a good operator overload, all three should be right. It's sometimes reasonable to do an overload where only two out of three are right, and the third isn't too far off. In this case, only one out of the three is even close to right; the other two are completely wrong.
Don't do this. It's a bad idea.
The following works, but you have to compile with the c++11 standard (g++ -std=c++11 *.cpp):
You can't use the XOR (^) operator for exponents with primitives. You have to overload it within a class.
#include <iostream>
#include <cmath>
#include <ctgmath>
using namespace std;
class Number {
private:
float _num;
public:
Number(float num) : _num(num){}
Number operator^(const float& num) {
return Number(pow(_num,num));
}
float get() {
return _num;
}
};
int main() {
Number a = Number(5);
Number b = a^7;
cout << b.get();
}
For primitive types (your case) :
In C and in C++, ^ is the bitwise XOR (exclusive-or) operator.
You should use std::pow to raise a number to a power.
For non primitive types, you could however overload operator^ (but it is discouraged since you would go against the usual meaning of this operator)
Example:
MyClass operator^(const MyClass& t1, const MyClass& t2)
{
//return ...
}
You can't do this for primitive types. You'll need to use std::pow. You can do it for user-defined types by overloading the ^ operator, but it may not be a good idea unless XOR makes no sense for your type.
(10 minutes after I say this someone will come up with a horrible, horrible hack for primitive types with a user-defined type, implicit conversions, a user-defined literal, and an overloaded ^ operator.)
pow() in the cmath library. More info on
http://en.cppreference.com/w/cpp/numeric/math/pow
it seems you are looking for someone to say write a^b :D
you should use predefined functions or write a new one ;)

C++ operator overloading takes pointer type as parameter?

I'm new to C++ and trying to figure out the differences between pointer and reference. I've just read this short summary.
In the article, the author mentioned that day *operator++ (day *d); won't compile (note: day is an enum type) and argued that the parameter for this overloaded operator function must be type T, T&, or T const&, where T is a class or enum type.
I assume that pointer is a built-in type rather than a class or enum so it can't be used to overload operators and that operator overloading is not possible for all built-in types such as int and double.
For example, int i = 1; ++i; would never result in i being 3 by overloading the ++ operator for the type int.
Am I correct? Please help me understand this problem better.
First rule in Operator overloading is:
You cannot overload operators for built-in data types, You can only for your custom data types, So you are correct in that regard.
Yes, pointer are primitive types and not objects. They are just numbers (the memory address of the object they point to), and as such arithmetics can be applied to them.
Yes, you cannot overload operators for primitive types (you can however overload binary operators in a class that take a primitive type parameter).

member binary operator and nonmember binary operator in operator overloading

While trying to learning operator overloading, I read the following statements from C++ Primer. Frankly speaking, I do not quite understand what does the message that these statements want to deliver. The examples include defining both member binary operator and nonmember binary operator. Is there any difference when using them?
Ordinarily we define the arithmetic and relational operators as nonmember functions and we define assignment operators as members:
Sales_item& Sales_item:: operator (const Sales_item&)
Sales_item operator_(const Sales_item&, const Sales_item&);
Both addition and compound assignment are binary operators, yet these functions define a different number of parameters. The reason for the discrepancy is the this pointer.
Yes, there is a difference in actual use. In particular, when you overload an operator as a non-member function, conversions can be applied to either operand (or both operands). When you overload a binary operator with a member function, conversions can only be applied to the right operand.
This can lead to some oddities. For example, consider writing a "bignum" package and you wanted to overload operator+ to handle bignums. If you overload it as a member function, you get an oddity like this:
int x = 2;
bignum y = 3;
bignum z;
z = y + x; // works fine.
z = x + y; // doesn't work: x isn't a bignum, and can/won't be converted to one
If, instead, you overload operator+ using a non-member function, both of the operations will work (presuming you have a constructor to create a bignum from an int, which you'd almost certainly want).
A few operators (particularly assignment operators, such as =, +=, -=, etc.) are special. A conversion creates a temporary object, and assigning to a temporary object 1) isn't allowed, and 2) wouldn't make sense or accomplish much anyway. Therefore, when you're overloading assignment operators, you always use a member function.

Odd behavior with operator>= overloading

I'm having a strange behavior with an operator overloading in C++. I have a class, and I need to check if its contents are greater or equal to a long double. I overloaded the >= operator to make this check, my declaration is as follows:
bool MyClass::operator>=(long double value) const;
I have to say that I also have a cast-to-long-double operator for my class, that works without exceptions only under certain conditions.
Now, when I use this operator, the compiler complains that there's an ambiguous use of operator>= and the alternatives are:
Mine.
The built-in operator>=(long double, int).
Now, how do I force the program to use my operator?
2015 update: Or, if you want to keep conversion ability using the (double)obj syntax instead the obj.to_double() syntax, make the conversion function explicit by prefixing it with that keyword. You need an explicit cast then for the conversion to trigger. Personally, I prefer the .to_double syntax, unless the conversion would be to bool because in that case the conversion is used by if(obj) even if it is explicit, and that is considerably more readable than if(obj.to_bool()) in my opinion.
Drop the conversion operator. It will cause troubles all the way. Have a function like
to_double()
Or similar that returns the double value and call that function explicitly to get a double.
For the problem at hand, there is this problem:
obj >= 10
Consider that expression. The builtin operator matches the first argument by a user defined conversion sequence for your type using the conversion operator long double(). But your function matches the second argument by a standard conversion sequence from int to long double (integral to floating point conversion). It is always ambiguous when there are conversions for two arguments, but not at least one argument that can be converted better while the remaining arguments are not converted worse for one call. In your case, the builtin one matches the second argument better but the first worse, but your function matches the first argument better but the second worse.
It's confusing, so here are some examples (conversions from char to int are called promotions, which are better than conversions from char to something other than int, which is called a conversion):
void f(int, int);
void f(long, long);
f('a', 'a');
Calls the first version. Because all arguments for the first can be converted better. Equally, the following will still call the first:
void f(int, long);
void f(long, long);
f('a', 'a');
Because the first can be converted better, and the second is not converted worse. But the following is ambiguous:
void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous
It's more interesting in this case. The first version accepts the first argument by an exact match. The second version accepts the second argument by an exact match. But both versions do not accept their other argument at least equally well. The first version requires a conversion for its second argument, while the second version requires a promotion for its argument. So, even though a promotion is better than a conversion, the call to the second version fails.
It's very similar to your case above. Even though a standard conversion sequence (converting from int/float/double to long double) is better than a user-defined conversion sequence (converting from MyClass to long double), your operator version is not chosen, because your other parameter (long double) requires a conversion from the argument which is worse than what the builtin operator needs for that argument (perfect match).
Overload resolution is a complex matter in C++, so one can impossibly remember all the subtle rules in it. But getting the rough plan is quite possible. I hope it helps you.
By providing an implicit conversion to a double you are effectively stating, my class is equivalent to a double and for this reason you shouldn't really mind if the built in operator >= for doubles is used. If you do care, then your class really isn't 'equivalent' to a double and you should consider not providing an implicit conversion to double, but instead providing an explicit GetAsDouble, or ConvertToDouble member function.
The reason that you have an ambiguity at the moment is that for an expression t >= d where t is an instance of your class and d is a double, the compiler always has to provide a conversion of either the left hand side or the right hand side so the expression really is ambiguous. Either t's operator double is called and the built-in operator >= for doubles is used, or d must be promoted to a long double and your member operator >= is used.
Edit, you've updated your question to suggest that your conversion is to long double and your comparison is against an int. In which case the last paragraph should read:
The reason that you have an ambiguity at the moment is that for an expression t >= d where t is an instance of your class and d is an int, the compiler always has to provide a conversion of either the left hand side or the right hand side so the expression really is ambiguous. Either t's operator long double is called and the built-in operator >= for long double and int is used, or d must be promoted to a long double and your member operator >= is used.
I assume you are comparing against a literal int, and not a long double:
MyClass o;
if (o >= 42)
{
// ...
}
If that is the case both alternatives are as good/complex.
Using your operator long double():
MyClass::operator long double()
built-in operator>=(long double, int)
Using your MyClass::operator>=(long double):
built-in conversion int to long double
MyClass::operator>=(long double)
You've got long double in the declaration. Try changing it to double.
Your use of operator overloading combined with custom casting can be very confusing to users of your class. Ask yourself, would users of this class expect it to convert itself into a double, or be comparable with a double? Wouldn't having a .greaterThan(double) function achieve the same goal but without surprising the user?
I guess you could always explicitly cast your object to double before comparing, to avoid the ambiguity. But if I were you I'd reconsider the approach above and focus on writing code that's intuitive and behaves in an unsurprising manner, instead of fancy type-casting and operator overloading.
(Inspired by the FQA's wonderful rant about operator overloading)
The built-in operator>=(long double, int).
Looks like you've defined:
bool class::operator>=(long double value) { return value >= classValue; }
And you are missing:
bool class::operator>=(double value) { return value >= classValue; }
bool class::operator>=(int value) { return value >= classValue; }
So the compiler can't decide which way to convert. (It's ambiguous.)
Perhaps a templated function (or method) would be helpful?
Watch out for situations where a>=b invokes different methods than b>=a.