Implicitly convert integers to class 'BigInt' - c++

I've made this class BigInt, and it it has derived transformation constructors such as
BigInt::BigInt(int l):InfInt(l){}
Yet when I do something like this:
for(i=0;BigInt::pow(2,i+1)<exponent;i++);
The compiler yells at me for:
error: ambiguous overload for ‘operator+’ (operand types are ‘BigInt’ and ‘int’)
I know a simple way to fix this is simply to add (BigInt) in front of everything, like this:
for(i=0;BigInt::pow(2,i+(BigInt)1)<exponent;i++);
But this code looks ugly, somewhat hard to read, and is a pain to type. Is there a way to tell the compiler to do this right away (as the title already says) ? It's not too dramatic if there isn't though.
Oh, and excuse me if this has been already asked, but I have tried to search for a solution on my own on google and here and have found nothing that could help me out. (I was mostly able to find stuff about operator int() and the like, which I already knew about).

You also have an operator int(), don't you? That, plus the constructor that takes an int, produces the ambiguity. The compiler can call BigInt::operator+() by converting the int argument to a BigInt, or it can call the built-in + by converting the BigInt object to an int. Mark the operator int() explicit to get rid of this ambiguity. That will lead to failed conversions in a few situations, which can be resolved by adding a cast. That's the best you can do; there are no conversion precedence rules that can make the compiler see BigInt as the largest integral type.

Not sure what the problem is. Does comparing against this help:
#include <iostream>
struct MyInt
{
MyInt(int i) : m_i(i) {}
MyInt operator+(const MyInt& myint) const
{
return MyInt(m_i+myint.m_i);
}
int m_i;
};
int main()
{
MyInt a(10);
MyInt b(5);
MyInt c1 = a + b;
MyInt c2 = a + 5;
std::cout << c1.m_i << std::endl;
std::cout << c2.m_i << std::endl;
return 0;
}

Related

How does the syntax for overloading post-increment operator in c++ work?

int operator++(int){
//relevant code
}
I dont seem to understand the workings of the code for overloading post increment operator given
above
I know that the int as a dummy parameter is given to differentiate between pre-increment and post increment operator overloading.
If a is a object of the class in which these operators are overloaded ,both ++a and a++ should have a equivalent representation as a.operator++()(as per my understanding ),how does the int parameter help in resolving it as a post increment operator?
-A c++ beginner
If a is a object of the class in which these operators are overloaded
,both ++a and a++ should have a equivalent representation as
a.operator++()(as per my understanding ),how does the int parameter
help in resolving it as a post increment operator?
The post increment operator can be called with a dummy int argument but normally this isn't what you would do. In the following, typically you would define void foo::operator++(int) so that you can make a call like (1) but (2) is legal.
#include<iostream>
struct foo {
void operator++() {
std::cout << "pre\n";
}
void operator++(int) {
std::cout << "post\n";
}
};
int main() {
foo a;
// these yield: pre
++a;
a.operator++();
// these yield post:
a++; // (1)
a.operator++(int{}); // (2)
}
When the compiler sees ++a, and a is not a built-in type, then the compiler looks for either a::operator++() or operator++(a&) and if found then calls it.
When the compiler sees a++, and a is not a built-in type, then the compiler looks for either a::operator++(int) or operator++(a&, int) and if found then calls it.
See Increment/decrement operators on cppreference.com for more details.

C++ generic rvalue overload

I'm currently trying to refactor some code which uses a primitive type into something which I can tuck setters and getters into them. I wanted to make the change to the underlying code transparent, and at first I though C++'s operator overloads would help me out there.
Let's suppose I want to make an "augmented int" type, for instance, that can be treated just like a regular int, but allows for further action wherever I assign to it, and just assignment - all other properties of an int, such as adding with +=, should be preserved.
At first I first though that if I encapsulated the int inside some struct, and filled out the operator= overloads, I'd be set, like in the following example:
#include<iostream>
typedef struct PowerInt{
int x;
PowerInt(){
cout << "PowerInt created\n";
x = 0;
}
~PowerInt(){
cout << "PowerInt destroyed\n";
}
void operator=(int other){
cout << "PowerInt received " << other << "\n";
this->x = other;
}
}PowerInt;
int main(){
PowerInt a;
a = 3;
return 0;
}
The code compiles and runs as expected, but as soon as I try making anything else a regular int could do, like cout << a, or a += 2, or even a simple int b = a; assignment the compiler complains about the operators << and += missing.
Fair enough; I then though that, at least for << and "assigment =", I could get by using some sort of "generic rvalue operator", or some kind of method which returns PowerInt.x wherever my a is used as an rvalue, automatically making expressions like int c = (a + 3); and if (a == 3) {} valid.
Problem is, I can't find a way to implement this idiom, and this mostly likely has to do with either my little understanding of how operator overloading works in C++, or some language feature I'm not yet aware of. Is it possible to accomplish what I'm trying here?
If you want your PowerInt to be convertible to a normal int you can create a user-defined conversion operator:
operator int() const
{
return x;
}
Any operator that's not defined for PowerInt will then use the operator defined for a normal int.
P.S The typedef struct isn't necessary in C++.

Calling the parenthesis overload given a pointer

I can overload the parenthesis operator using the following signature:
char& operator()(const int r, const int c);
The intended usage of this would be:
// myObj is an object of type MyClass
myObj(2,3) = 'X'
char Y = myObj(2,3);
Which works as I expect. However, using the parenthesis operator when dealing with a pointer becomes convoluted. I would like to do:
// pMyObj is a pointer to an object of type MyClass
pMyObj->(2,3) = 'X';
char Y = pMyObj->(2,3);
However, such syntax yields the error Error: expected a member name (in VisualStudio at least).
The following does work but seems convoluted to me with a dereference and more parentheses than arguments.
char X = (*pMyObj)(2,3);
Is there a way to use the -> operator to call the () overload?
Yes there is, but you won't like it:
pMyObj->operator()(2,3);
You could also create a reference to the pointed to object and do
MyObj& rMyObj = *pMyObj;
char Y = rMyObj(2, 3);
which might be a good alternative if your code will be read by people who could be confused by
pMyObj->operator()(2,3);
if you do as below
#define SUB operator()
Then you can write things like this ...
pMyObj->SUB(2,3)
not as elegant as Fortran ;-) but perhaps not too ugly for actual use

C++ Implicit Conversion Operators Precedence

EDIT: Following Mike Seymour's comment, I replaced operator std::string () const; with operator char * () const; and changed the implementation accordingly. This allows implicit casting, but, for some reason, the unsigned long int operator has precedence over the char * operator, which just does not feel right... Also, I don't want to expose nasty C stuff like char * outside the class, when I have std::string. I have a hunch that my CustomizedInt class needs to inherit from some stuff in order to support the feature that I desire. Could anybody please elaborate Mike's comment regarding std::basic_string? I'm not sure I understood it properly.
I have this piece of code:
#include <string>
#include <sstream>
#include <iostream>
class CustomizedInt
{
private:
int data;
public:
CustomizedInt() : data(123)
{
}
operator unsigned long int () const;
operator std::string () const;
};
CustomizedInt::operator unsigned long int () const
{
std::cout << "Called operator unsigned long int; ";
unsigned long int output;
output = (unsigned long int)data;
return output;
}
CustomizedInt::operator std::string () const
{
std::cout << "Called operator std::string; ";
std::stringstream ss;
ss << this->data;
return ss.str();
}
int main()
{
CustomizedInt x;
std::cout << x << std::endl;
return 0;
}
Which prints "Called operator unsigned long int; 123". My questions are these:
After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? Why does it not call the implicit cast operator (std::string) directly?
Is there any documentation that explains which implicit casts are allowed and which is their order of precedence? It seems that if I add an operator unsigned int to this class together with the operator unsigned long int, I receive a compiler error about ambiguity for the << operator...
Also, I know that defining such an operator may be poor practice, but I am not sure I fully understand the associated caveats. Could somebody please outline them? Would it be better practice to just define public methods ToUnsignedLongInt and ToString?
After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? Why does it not call the implicit cast operator (std::string) directly?
The version of << for strings is a template, parametrised by the parameters of the std::basic_string template (std::string itself being a specialisation of that template). It can only be chosen by argument-dependent lookup, and that only works if the argument is actually a specialisation of std::basic_string, not something convertible to that.
Is there any documentation that explains which implicit casts are allowed and which is their order of precedence?
The rules are quite complex, and you'd need to read the C++ standard for the full story. Simple rules of thumb are that implicit conversions can't contain more than one user-defined conversion and (as you've found out) the result of an implicit conversion can't be used to choose a template specialisation by argument-dependent lookup.
I am not sure I fully understand the associated caveats. Could somebody please outline them?
I don't fully understand them either; the interactions between implicit conversions, name lookup and template specialisation (and probably other factors that I can't think of right now) are rather complex, and most people don't have the inclination to learn them all. There are quite a few instances where implicit conversion won't happen, and others where it might happen when you don't expect it; personally, I find it easier just to avoid implicit conversions most of the time.
Would it be better practice to just define public methods ToUnsignedLongInt and ToString?
That's probably a good idea, to avoid unwanted conversions. You can fix your problem by leaving them and use them explicitly when necessary:
std::cout << std::string(x) << std::endl;
In C++11, you can declare them explicit, so that they can only be used in this manner. In my opinion, that would be the best option if you can; otherwise, I would use explicit conversion functions as you suggest.
By the way, the return type of main() must be int, not void.

Why my implicit conversion function doesn't work?

I have a wrapper class and I want to modify the data and convert it back to its original type.
class A
{
public:
A ( unsigned __int64 _a ) : a (_a)
{
}
operator unsigned __int64 () const
{
return a;
}
unsigned __int64 a;
};
I want the object of this class to implicitly convert back to unsigned __int64, but it failed.
Say,
A a( 0x100ull );
unsigned __int64 b = (a >> 16); // Error
Compiler gives C2678 error, no operator found or there is no acceptable conversion.
It seems this function operator unsigned __int64 () const doesn't work.
To be more specific, compiler says there is no acceptable conversion. I cannot accept the complain, because I have already given a good one. Can someone legitimize it?
It doesn't work because you haven't created an operator>> overload for your class that takes an integer and does something with it.
I'm guessing you're trying to do a right shift on your int, but I'm not sure that overloading your operator>> is a good idea for that, as these operators in a context like that, are normally used for streaming. It might confuse a reader or maintainer of your code afterwards.
See here for more info on operator overloading
Perhaps rethink your implementation strategy?