7

The following overloaded function,

void foo(const void*)
{
  printf("first");
}

void foo(unsigned int)
{
  printf("second");
}

generates an ambiguous overload in this case

foo((int)0);

but not in this one

foo((int)1);

Why? Is it because people still use NULL? And what's the best way to get around the problem, without explicit cast?

(I'm compiling with GCC 8.3.0-C++11 on Ubuntu 18.04)

Godbolt conformance view

EDIT

As some of you pointed out in the comments, (int)0 compiles without errors, actually (at least on GCC 8.3.0, with C++11 std). The problem I had was only with foo(0), and I get why now.

Sneppy
  • 379
  • 5
  • 20
  • Indeed NULL. Why do you need an overloaded function? Can't you use different functions? – JHBonarius Oct 18 '20 at 11:30
  • 3
    Thing is, `(int)0` shouldn't cause an ambiguity. Only a literal `0` constitutes a null pointer constant. A cast expression does not. What compiler options did you build with? – StoryTeller - Unslander Monica Oct 18 '20 at 11:35
  • 1
    Yeah, I cannot reproduce your problem https://wandbox.org/permlink/GKRgIv2CTNZ7XhR9 - For `(int)0` the second overload is called, as expected. – StoryTeller - Unslander Monica Oct 18 '20 at 11:37
  • 1
    I can reproduce this [here](https://godbolt.org/z/5G9Y44) with gcc, not with clang. – ChrisD Oct 18 '20 at 11:40
  • @StoryTeller-UnslanderMonica, I'm able to reproduce the problem in MingW64 gcc. – anastaciu Oct 18 '20 at 11:49
  • Apperantly in C++98 mode even `const int i = 0; foo(i);` causes an error with current versions of GCC and clang. [Demo here](https://godbolt.org/z/xGGvfM). – IlCapitano Oct 18 '20 at 11:49
  • @anastaciu - And I'll ask you the same thing I asked the OP, with *what options*? Simply using MingW64 says nothing. – StoryTeller - Unslander Monica Oct 18 '20 at 11:51
  • 2
    @IlCapitano - It should in C++98 mode. A defect http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#903 that wasn't retroactively applied to C++03 is at play here. – StoryTeller - Unslander Monica Oct 18 '20 at 11:51
  • msvc fails, gcc/clang is fine if C++11 is enabled: https://godbolt.org/z/9Yr7sj – Marek R Oct 18 '20 at 11:55
  • @StoryTeller-UnslanderMonica, no options, `g++ main.cpp`, default `std=c++14`. But I see your link, in any case the problem stands in my compiler. – anastaciu Oct 18 '20 at 12:03
  • Yes, sorry my bad, `(int)0` doesn't cause ambiguity, whereas `0` does. – Sneppy Oct 18 '20 at 15:05
  • 1
    Interestingly if you remove `foo(unsigned int)` from the overload resolution, the code does not compile. I am not sure why the function `foo (const void*)` is not removed from the candidate list if with two candidates the call is ambiguous but calling the only candidate `foo(const void*)` with `(int)0` is incorrect. – NotAProgrammer Oct 18 '20 at 15:10

2 Answers2

6

The literal 0 has special meaning in C and C++, as it's also a null pointer literal. This is how NULL works.

If you're calling the function with a literal, instead of foo(0) you could do foo(0u), which works because 0u already has the type unsigned int, so there's no conversion needed to call the integer overload. If you're calling foo with an integer variable, there shouldn't be any conflict. (demo here)

As mentioned in the comments, (int)0 shouldn't cause any conflict, and GCC 8.3 doesn't produce any error with foo((int)0) in C++11 mode, but does in C++98 mode (and so does clang). As mentioned by @StoryTeller-UnslanderMonica in the comments, this is caused by a defect http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#903 that wasn't retroactively applied to C++98.

IlCapitano
  • 1,994
  • 1
  • 7
  • 15
0

In situations like yours, you can usually help yourself with SFINAE or requires(). Here is an idea, but other solutions are also possible:

void foo(void const*)
{
  printf("first");
}

void foo(auto a)
  requires(
    std::is_integral_v<decltype(a)> &&
    !std::is_same_v<decltype(NULL), decltype(a)>
  )
{
  printf("second");
}

Demo

But, NULL does not usually present a problem in c++.

user1095108
  • 14,119
  • 9
  • 58
  • 116