intabs(int) 与 doubleabs(double)

发布于 2025-01-09 00:58:39 字数 548 浏览 1 评论 0原文

我想从 C++ 标准的角度(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
}

因此,int abs(int) 被导入到全局命名空间,而 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

维持三分热 2025-01-16 00:58:39

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

来自 cppreference

对于某些 xxx.h 形式的 C 标准库头文件,C++
标准库都包含一个同名的头文件和另一个
cxxx 形式的标头(列出了所有有意义的 cxxx 标头
多于)。 xxx.h 形式的标头的预期用途是
仅互操作性。 C++ 源文件可能需要
包含这些标头之一才能成为有效的 ISO C. 源文件
不打算同时有效的 ISO C 不应使用任何
C 头文件。

除了complex.h之外,每个xxx.h头都包含在
C++ 标准库将每个名称放置在全局命名空间中
相应的 cxxx 标头将放置在 std 命名空间中。

这些标头也可以在 std 中声明相同的名称
命名空间,以及相应的 cxxx 标头也被允许
在全局命名空间中声明相同的名称:包括
肯定提供 std::malloc 并且也可能提供::malloc。
包括 肯定提供::malloc,也可能提供
std::malloc。这甚至适用于函数和函数重载
不属于 C 标准库的一部分。

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

cstdlib is the C++ version of the C header stdlib.h. Such headers must introduce the names in the std namespace and they are allowed to introcude them in the global namespace. There is no double abs(double) in the C header, hence there is no reason to introduce it in the global namespace like it is done for the C variants of the funciton. Note that C has no namespaces, and having the function in the global namespace helps for compatibility with C code. For double abs(double) this is not an issue, because the function does not exist in the C header.

From 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.

This applies even to functions and function overloads that are not part of C standard library. That means: It would be allowed to have double abs(double) in the global namespace too, but it is not required.

微暖i 2025-01-16 00:58:39

因此,int abs(int)被导入到全局命名空间中,

为什么?

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

虽然双腹肌(double)不是!

为什么?

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


相关标准报价:

[标题]

除了 [library] 到 [thread] 和 [depr] 中注明的内容外,每个头文件 cname 的内容与 C 标准库中指定的相应头文件 name.h 的内容相同。
然而,在 C++ 标准库中,声明(除了在 C 中定义为宏的名称)位于命名空间 std 的命名空间范围内。
未指定这些名称(包括通过 [thread] 和 [depr] 在 [support] 中添加的任何重载)是否首先在全局命名空间范围内声明,然后通过显式 using 声明([namespace.udecl] 注入到命名空间 std 中) )。


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

另一种可能的结果是 abs(0.1) 由于使用未声明的标识符而失败。您不能依赖在全局命名空间中声明的 C++ 标准库名称(除非您使用已弃用的 C 标准标头)。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文