I'm getting compiler errors when I call abs()
with GCC's 128 bit type. My line looks like:
__extension__ using int128_t = __int128;
int128_t mantissa_;
// Other code
using namespace std;
int128_t temp = abs(mantissa_);
The error I'm getting locally is:
error: call of overloaded ‘abs(const int128_t&)’ is ambiguous
int128_t temp = abs(mantissa_);
/usr/include/stdlib.h:840:12: note: candidate: ‘int abs(int)’
840 | extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
/usr/include/c /11/bits/std_abs.h:56:3: note: candidate: ‘long int std::abs(long int)’
56 | abs(long __i) { return __builtin_labs(__i); }
| ^~~
/usr/include/c /11/bits/std_abs.h:61:3: note: candidate: ‘long long int std::abs(long long int)’
61 | abs(long long __x) { return __builtin_llabs (__x); }
| ^~~
/usr/include/c /11/bits/std_abs.h:71:3: note: candidate: ‘constexpr double std::abs(double)’
71 | abs(double __x)
| ^~~
/usr/include/c /11/bits/std_abs.h:75:3: note: candidate: ‘constexpr float std::abs(float)’
75 | abs(float __x)
| ^~~
/usr/include/c /11/bits/std_abs.h:79:3: note: candidate: ‘constexpr long double std::abs(long double)’
79 | abs(long double __x)
so it's not considering my overload (below) as a candidate?
namespace std
{
__extension__ using int128_t = __int128;
int128_t abs(int128_t x)
{
return x < 0 ? x * -1 : x; // Not ideal but no builtin for 128
}
}
Is the overload correct?
However, when I mock an example in Godbolt, even without overloading abs()
, it compiles fine:
https://godbolt.org/z/P8T1fGxcK
#include <iostream>
__extension__ using int128_t = __int128;
struct Decimal
{
Decimal(int128_t q) : mantissa_(q)
{
volatile int128_t x = abs(mantissa_); // How is this compiling?
std::cout << "ctor" << std::endl;
}
int128_t mantissa_;
};
int main()
{
Decimal dec(-6);
}
Are Godbolt using a library like Abseil, they're providing a function and that's why it is compiling?
CodePudding user response:
tl;dr
Remove using namespace std;
or call the builtin directly (__int128 temp = __builtin_abs(mantissa_);
)
Note that __int128
is a gcc-specific compiler extension (so non-portable code)
Why the godbolt works
gcc will automatically treat a set of common c functions as builtins:
6.59 Other Built-in Functions Provided by GCC
The ISO C90 functions
abort
,abs
,acos
, [...],vprintf
andvsprintf
are all recognized as built-in functions unless-fno-builtin
is specified (or-fno-builtin-function
is specified for an individual function). All of these functions have corresponding versions prefixed with__builtin_
.
So when you compile a program like the following the call to abs
will automatically be interpreted as __builtin_abs
:
godbolt
int main() {
__int128 foo = 1;
// equivalent to __int128 absFoo = __builtin_abs(foo);
__int128 absFoo = abs(foo);
}
The builtin variants of those functions do support __int128
, therefore this works.
Note that this builtin-transformation ONLY works in case overload resolution determines that abs(foo)
would call the c function abs
and ONLY if you're compiling without -fno-builtin
.
i.e. the c variant of abs
- std::abs
- will NOT be transformed into its builtin-equivalent and therefore this will not compile (there is no overload for _int128
):
godbolt
int main()
{
__int128 foo = 1;
// ambigous function call - there is no overload for __int128
__int128 absFoo = std::abs(foo);
}
Why your code example doesn't work
Your code example contains using namespace std;
- this will bring std::abs
into scope which will prevent the abs(mantissa_)
call from being treated as a builtin (and due to std::abs
having no overload for __int128
you'll get an ambigous function call error)
To make this work you basically have 2 options:
- Don't use
using namespace std;
and rely on the builtin-transformation gcc provides, e.g.:/*using namespace std;*/ int128_t temp = abs(mantissa_);
- Explicitly call the builtin you want to use:
int128_t temp = __builtin_abs(mantissa);