I have a program which lets C++ support arbitrary precision numbers (very large numbers). Takes datatype as string or string literals. Basically "762...."
Compiler: g++ (Debian 10.2.1-6) 10.2.1 20210110
I have class big_int, and it handles all the things. I also have operator overloads that cleanly handles the arithmetic and assignments.
There is one problem, I can't copy initialize string literals for big_int objects
Rough definition of my class:
class big_int {
// operator overloads
// Constructors
big_int (){}
big_int (const big_int& other){ *this = other;} // has the =overload for direct copying
explicit big_int (const char* s){ value = s;}
big_int (const std::string& s){ value = s;}
}
int main(){
big_int num2 = "99"; // doesn't work
}
``
> error:conversion from ‘const char [3]’ to non-scalar type ‘big_int’ requested big_int num2 = "99";
Even tough this works
```cpp
int main(){
big_int str_num("45569");
}
I have the following operator overloads (I don't think this info is necessary, but still):
class big_int {
public:
// Member Operator Overloads -> ->
// assingment overloads
// std::string
big_int& operator=(const std::string& other) { // = overload (strings)
this->value = other; // no self assingment
return *this; // de-referenced object
}
// big_int
big_int& operator=(const big_int& other) { // = overload (big_int)
if (this != &other) this->value = other.value; // no self assingment
return *this; // de-referenced object
}
// --------------------------
// plus overloads
// std::string
big_int operator+(const std::string& other) const{ // + overload (strings)
return big_int(arb_add(value, other));
}
// big_int
big_int operator+(const big_int& other) const{ // + overload
return big_int(arb_add(value, other.value));
}
// -----------------------
// minus overloads
// std::string
big_int operator-(const std::string& other) const{ // - overload
return big_int(arb_sub(value, other));
}
// big_int
big_int operator-(const big_int& other) const{ // - overload
return big_int(arb_sub(value, other.value));
}
// -------------------------------
}
// GENERAL OPERATOR OVERLOADS
std::ostream& operator<<(std::ostream& os, const big_int& other) {
os << other.value;
return os;
}
// ========================
I am trying to copy initialize my custom datatype with string literals, expecting this:
int main() {
big_int num2 = "99"; // copy initialization
std::cout << num2 << std::endl; //should print 99 (direct printing of type possible because of << overload)
}
But g++ gave this error
main.cpp: In function ‘int main()’:
main.cpp:300:18: error: conversion from ‘const char [3]’ to non-scalar type ‘big_int’ requested
300 | big_int num2 = "99"; // error: conversion from ‘const char [3]’ to non-scalar type ‘big_int’ requested big_int num2 = "99"
| ^~~~
Even tough this works
int main() {
big_int str_num("45569");
}
The problem is that I have the required constructors for it work, but it completely denies to do that.
When the 'explicit' is removed, it causes ambiguous overloads with operator= and all member operator overloads.
"99"
is a c-string literal, it has the the type const char[3]
. When you do
big_int num2 = "99";
since the types do not match the compiler tries to convert "99"
to something that can be used to initialize a big_int
.
It can't use
explicit big_int (const char* s)
because the constructor is marked as explicit.
It also can't use
big_int& operator=(const std::string& other)
because even though there is an =
used, we are initializing, not assigning so the assignment operators can't be used.
This means there is no implicit way to convert "99"
into something that can initialize a big_int
. You either need to explicitly do it, or remove the explicit from the constructor.
Common guidance is to not remove the explicit
as non explicit converting constructors can lead to some unexpected behavior.