15

I'm running a simple C++ program from HackerRank about pointers and it works fine on the website. However, when I run it on MacOS, I get error: call to 'abs' is ambiguous and I'm not sure exactly what is ambiguous.

I've looked at other answers to similar issues, but the error message tends to be Ambiguous overload call to abs(double), which is not the issue I'm having, since I haven't used any doubles. I've also tried including the header files cmath and math.h, but the problem persists.

#include <stdio.h>
#include <cmath>

void update(int *a,int *b) {
    int num1 = *a;
    int num2 = *b;
    *a = num1 + num2;
    *b = abs(num1 - num2);
}

int main() {
    int a, b;
    int *pa = &a, *pb = &b;

    scanf("%d %d", &a, &b);
    update(pa, pb);
    printf("%d\n%d", a, b);

    return 0;
}

My issue occurs with line 8.

AkThao
  • 582
  • 4
  • 7
  • 23
  • I don't know, but `abs` is in ``. – melpomene Jul 10 '19 at 20:46
  • 4
    Use `std::abs` and you shouldn't have a problem. – NathanOliver Jul 10 '19 at 20:46
  • 1
    @melpomene since `C++17`, `std::abs` is defined in ``. [Source](https://en.cppreference.com/w/cpp/numeric/math/abs). – Fureeish Jul 10 '19 at 20:47
  • 1
    I get the same error when I use `std::abs` but the error disappears and the code works when I use `#include `. – AkThao Jul 10 '19 at 20:48
  • Can't reproduce with latest C++, please indicate dialect. – SergeyA Jul 10 '19 at 20:49
  • @SergeyA I think I'm using C++11 though I don't know how to find out. – AkThao Jul 10 '19 at 20:52
  • @AkThao what compiler are you using? –  Jul 10 '19 at 21:08
  • @Chipster I'm using G++. `LLVM version 9.0.0` comes up when I type `g++ --version` in terminal. – AkThao Jul 10 '19 at 21:09
  • @AkThao Ugh. I'm not familiar with it to tell you how to find out. But maybe someone else is. In order to help that person, could you also indicate what version of the compiler you are using? –  Jul 10 '19 at 21:10
  • I think I found the version. It's G++ 4.2.1. – AkThao Jul 10 '19 at 21:19
  • So the bug goes away when you use C++ header files in a C++ program, but is present if you use C header files in a C++ program. Hmmmm. – Eljay Jul 10 '19 at 21:20
  • 1
    @Eljay Well you're not supposed to use the `.h` C header files in C++. – eesiraed Jul 10 '19 at 21:22
  • If you're on macOS and you didn't go out of your way to install GCC, `gcc` and `g++` are aliased to `clang` and `clang++`. You can get the compiler version with `clang --version`. – zneak Jul 10 '19 at 21:22
  • @zneak I get `Apple LLVM version 9.0.0 (clang-900.0.39.2) Target: x86_64-apple-darwin16.7.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin` when using `clang --version`. I assume the first line is the compiler version. – AkThao Jul 10 '19 at 21:27

5 Answers5

12

The full error message is:

$ clang++ test.cpp
test.cpp:8:10: error: call to 'abs' is ambiguous
    *b = abs(num1 - num2);
         ^~~
.../include/c++/v1/math.h:769:1: note: candidate function
abs(float __lcpp_x) _NOEXCEPT {return ::fabsf(__lcpp_x);}
^
.../include/c++/v1/math.h:769:1: note: candidate function
abs(double __lcpp_x) _NOEXCEPT {return ::fabs(__lcpp_x);}
^
.../include/c++/v1/math.h:769:1: note: candidate function
abs(long double __lcpp_x) _NOEXCEPT {return ::fabsl(__lcpp_x);}
^
1 error generated.

The three overloads of abs that you have from <cmath> are abs(float), abs(double) and abs(long double); it's ambiguous because you have an int argument and the compiler doesn't know which floating-point type to convert to.

abs(int) is defined in <cstdlib>, so #include <cstdlib> will resolve your problem.

If you're using Xcode, you can get more details about the error in the Issues navigator (⌘5) and clicking the triangle next to your issue.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • 1
    So does that mean abs(int) is not defined in `` and if so, why not? – AkThao Jul 10 '19 at 20:49
  • @AkThao, the reasons are probably historic, as C originally did not have floating-point types. My guess is that floating-point support used to be optional, and they started by having it all in `math.h`. I can't name off the top of my head a function in math.h that doesn't mainly use floating-point types, and I can only name a handful of functions outside of it that use them. – zneak Jul 10 '19 at 20:52
  • 2
    I now have a slightly better answer: `std::abs` was only introduced in C++17. Prior to that, you had to use `std::fabs` to get a floating-point absolute value, and your same program would have complained that `abs` did not exist instead (possibly highlighting better that you were missing the correct `#include`). – zneak Jul 10 '19 at 21:01
  • Is `fabs` the same as `abs(float)`, `abs(double)` and `abs(long double)`? Also, since using `std::abs` doesn't fix my code, does that mean I'm using a version earlier than C++17? On a slightly related note, how do I check what version of C++ I'm using (typing `C++ --version` into the terminal only gives compiler information)? – AkThao Jul 10 '19 at 21:06
  • 2
    `abs` and `fabs` are overloaded functions which perform different operations given different argument types. `fabs` is overloaded for all floating-point types, and `abs` is (in C++17, or as an extension in previous versions of C++) overloaded for all numeric types (integers and floating-point). Calling `abs(double)` should be the same as calling `fabs(double)`. – zneak Jul 10 '19 at 21:13
  • Regarding the C++ version you're using, I don't know if there's a very easy way to get an answer. The `__cplusplus` constant gives you a year and a month, but because platforms are allowed to define extensions, you can find yourself with C++17 capabilities in an environment that calls itself C++98, for instance. You can tell Clang that you want a specific dialect using the `--std=[...]` argument, where typical values would be `c++14`, `c++17`, or `gnu++14`, `gnu++17`. (The GNU versions include extensions defined by GCC.) – zneak Jul 10 '19 at 21:16
8

For me, #include <cstdlib> didn't solve the issue, maybe because I didn't have to include anything to use abs. So, in case it helps someone else, with explicit casting, it worked well for me like in the next code:

*b = abs(int(num1 - num2));
ana
  • 1,071
  • 9
  • 12
6

In templated code, it may be easily overlooked that std::abs is not defined for unsigned types. As an example, if the following method is instantiated for an unsigned type, the compiler may rightfully complain that std::abs is undefined:

template<typename T>
bool areClose(const T& left, const T& right) {
    // This is bad because for unsigned T, std::abs is undefined
    // and for integral T, we compare with a float instead of
    // comparing for equality:
    return (std::abs(left - right) < 1e-7);
}

int main() {
    uint32_t vLeft = 17;
    uint32_t vRight = 18;
    std::cout << "Are the values close? " << areClose(vLeft, vRight) << std::endl;
}

A better definition of areClose() in above code, that would coincidentally also solve the problem of std::abs() being undefined, could look like this:

template<typename T>
bool areClose(const T& left, const T& right) {
    // This is better: compare all integral values for equality:
    if constexpr (std::is_integral<T>::value) {
        return (left == right);
    } else {
        return (std::abs(left - right) < 1e-7);
    }
}
emmenlau
  • 958
  • 12
  • 20
1

if your using C compiler you should include

#include <stdlib.h>

and use abs without std::. If you use C++ compiler then you should change abs to std::abs.

Hope it helps:)

NewMe
  • 162
  • 4
  • 1
    I'm using a C++ compiler, but for some reason, using `std::abs` doesn't seem to make a difference. It only works when I use `#include `. – AkThao Jul 10 '19 at 21:01
  • That is weird.. I've tried two online C++ compilers and both works with just std::abs. Please look: https://ideone.com/wls3Tp https://onlinegdb.com/BJzbpcDZH – NewMe Jul 13 '19 at 18:03
  • It could be that I'm using an older version of C++. In the comments to the above answer, zneak said that `std::abs` was only introduced in C++17 and before that, `std::fabs` had to be used. This is what I'm experiencing, `std::abs` does not work but `std::fabs` does. In the terminal, I tried to specify the dialect using `-std=c++17`, but it returned an error saying `invalid value 'c++17'`. – AkThao Jul 14 '19 at 10:00
  • Using VS2019 defaults with a new C++ Windows Desktop Application. Only `#include ` or `#include ` gets abs for float. `stdlib.h` seems not to want to accept a float argument. :( – Laurie Stearn Mar 15 '20 at 07:10
-3

I used #include <bits/stdc++.h> as the only include statement and it worked for me. My code:

#include <bits/stdc++.h>  
using namespace std;
class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        int n = nums.size();
        if(n == 0 || n == 1)
            return {};
        vector<int> ans;
        for(int i = 0; i < n; i++)
        {
            if(nums[abs(nums[i])-1] < 0)
                ans.push_back(abs(nums[i]));
            else
                nums[abs(nums[i])-1] = -1 * nums[abs(nums[i])-1];
        }
        return ans;
    }
};