gcc 无法为愚者128位整数重载std::abs()

w1jd8yoj  于 2022-12-13  发布在  其他
关注(0)|答案(1)|浏览(267)

当我用愚者的128位类型调用abs()时,我得到了编译器错误。我的代码行如下所示:

__extension__ using int128_t = __int128;

int128_t mantissa_;

// Other code

using namespace std;
int128_t temp = abs(mantissa_);

我在本地遇到的错误是:

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)

所以它不考虑我的超载(如下)作为候选人?

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
    }
}

过载是否正确?
然而,当我模拟Godbolt中的一个例子时,即使没有重载abs(),它也能很好地编译:
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);
}

Godbolt使用的是像Abseil这样的库吗,他们提供了一个函数,这就是为什么它在编译?

q0qdq0h2

q0qdq0h21#

tl; d文件

移除using namespace std;或直接呼叫内建(__int128 temp = __builtin_abs(mantissa_);
请注意,__int128是gcc特定的compiler extension(因此代码不可移植)
为什么神箭能用
愚者将自动地将一组通用C函数视为内置函数:
6.59 Other Built-in Functions Provided by GCC
除非指定-fno-builtin(或为个别函式指定-fno-builtin-function),否则ISO C90函式abortabsacos、[...]、vprintfvsprintf都会被辨识为内建函式。所有这些函式都有以__builtin_为前置词的Map版本。
所以当你编译一个类似下面的程序时,对abs的调用会自动被解释为__builtin_abs
godbolt

int main() {
  __int128 foo = 1;
  // equivalent to  __int128 absFoo = __builtin_abs(foo);
  __int128 absFoo = abs(foo);
}

这些函数的内置变体*支持__int128,因此可以正常工作。
请注意,这个内建转换
ONLY
在重载解析确定abs(foo)将调用c函数abs的情况下有效,ONLY如果您在没有-fno-builtin的情况下进行编译。
例如,abs-std::abs-的c++变体将NOT转换为它的内置等效项,因此不会编译(_int128没有重载):
godbolt

int main()
{
    __int128 foo = 1;
    // ambigous function call - there is no overload for __int128
    __int128 absFoo = std::abs(foo);
}
代码示例无法工作的原因

您的代码示例包含using namespace std;-这将使std::abs进入作用域,从而防止将abs(mantissa_)调用视为内置函数(由于std::abs没有__int128的重载,您将得到一个模糊的函数调用错误)
要实现这一点,您基本上有两种选择:

  • 不要使用using namespace std;,而要依赖gcc提供的内置转换,例如:
/*using namespace std;*/
int128_t temp = abs(mantissa_);
  • 显式调用要使用的内置函数:
int128_t temp = __builtin_abs(mantissa);

相关问题