c++language-lawyercmath

int abs(int) vs double abs(double)


I'd like to understand the behavior of the following code, from the C++ Standard point of view (GCC 9.3, C++20):

#include <cstdlib>

template<class> struct type_tester;
int main() {
    type_tester<decltype(abs(0.1))>{};      // int abs(int) overload is selected for some reason!
    type_tester<decltype(std::abs(0.1))> {}; // double abs(double) overload is selected, as one would expect
}

So, int abs(int) is imported to the global namespace, while double abs(double) is not!

Why?


Solution

  • So, int abs(int) is imported to the global namespace,

    Why?

    Because the C++ standard allows it to be imported into the global namespace.

    While double abs(double) is not!

    Why?

    Because the C++ standard doesn't require it to be imported into the global namespace.


    Relevant standard quotes:

    [headers]

    Except as noted in [library] through [thread] and [depr], the contents of each header cname is the same as that of the corresponding header name.h as specified in the C standard library. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope of the namespace std. It is unspecified whether these names (including any overloads added in [support] through [thread] and [depr]) are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations ([namespace.udecl]).


    Evidently, the C++ standard library implementation that you use had chosen to use the strategy described in the last paragraph of the quoted rule for the C standard library function, while having chosen not to use that strategy for the C++ standard library overloads. This specific outcome isn't guaranteed by the standard but it is conforming.

    Another possible outcome would be that abs(0.1) would fail as use of an undeclared identifier. You cannot rely on C++ standard library names to be declared in the global namespace (unless you use the deprecated <name.h> C standard headers).