int abs(int) vs double abs(double)

int abs(int) vs double abs(double)

我想从 C++ 标准(GCC 9.3、C++20)的角度了解 the following code 的行为:

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

因此,int abs(int) 被导入到全局命名空间,而 double abs(double) 不是!

为什么?

cstdlib是Cheaderstdlib.h的C++版本。这样的 header 必须引入 std 命名空间中的名称,并且允许它们在全局命名空间中引入它们。 C header 中没有 double abs(double),因此没有理由像函数的 C 变体那样在全局命名空间中引入它。请注意,C 没有名称空间,在全局名称空间中包含该函数有助于与 C 代码兼容。对于 double abs(double) 这不是问题,因为 C header.

中不存在该函数

来自cppreference

For some of the C standard library headers of the form xxx.h, the C++ standard library both includes an identically-named header and another header of the form cxxx (all meaningful cxxx headers are listed above). The intended use of headers of form xxx.h is for interoperability only. It is possible that C++ source files need to include one of these headers in order to be valid ISO C. Source files that are not intended to also be valid ISO C should not use any of the C headers.

With the exception of complex.h , each xxx.h header included in the C++ standard library places in the global namespace each name that the corresponding cxxx header would have placed in the std namespace.

These headers are allowed to also declare the same names in the std namespace, and the corresponding cxxx headers are allowed to also declare the same names in the global namespace: including <cstdlib> definitely provides std::malloc and may also provide ::malloc. Including <stdlib.h> definitely provides ::malloc and may also provide std::malloc. This applies even to functions and function overloads that are not part of C standard library.

这甚至适用于不属于 C 标准库的函数和函数重载。这意味着:也允许在全局命名空间中包含 double abs(double),但不是必需的。

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

Why?

因为C++标准允许将其导入全局命名空间。

While double abs(double) is not!

Why?

因为 C++ 标准不要求将其导入全局命名空间。


相关标准语录:

[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]).


显然,您使用的 C++ 标准库实现已选择对 C 标准库函数使用引用规则最后一段中描述的策略,而对 C++ 标准库选择不使用该策略过载。该特定结果不受标准保证,但符合标准。

另一个可能的结果是 abs(0.1) 会因为使用未声明的标识符而失败。您不能依赖在全局命名空间中声明的 C++ 标准库名称(除非您使用已弃用的 <name.h> C 标准头文件)。