【问题标题】:Why does <cmath> expose entities outside the std namespace?为什么 <cmath> 会暴露 std 命名空间之外的实体?
【发布时间】:2020-03-19 21:57:06
【问题描述】:

据我了解,C++ 使用的 C 实体(如 &lt;math.h&gt; 中的实体)可以通过包含相应的 &lt;c...&gt; 变体以安全的方式包含在 std 命名空间中(显然,宏除外)。 cppreference seems to confirm this.

但是,包括 &lt;cmath&gt; 似乎会拉入 log 函数std 命名空间之外

#include <cmath>

namespace log {}

int main() {}

使用g++ -Wall -Wextra -pedantic -std=c++17 a.cpp 编译产生:

a.cpp:3:11: error: ‘namespace log { }’ redeclared as different kind of entity
    3 | namespace log {}
      |           ^~~
In file included from /usr/include/features.h:446,
                 from /usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h:39,
                 from /usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h:524,
                 from /usr/include/c++/9/cmath:41,
                 from a.cpp:1:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:104:1: note: previous declaration ‘double log(double)’
  104 | __MATHCALL_VEC (log,, (_Mdouble_ __x));
      | ^~~~~~~~~~~~~~

我的标准库坏了吗?我可以做些什么来避免这种情况吗?


我最初是在使用 &lt;random&gt; 时偶然发现的,这意味着更多的标头可能会受到明显随机的 C 实体的影响。

【问题讨论】:

  • "...以及相应的 cxxx 头文件也允许在全局命名空间中声明相同的名称..." 来源:en.cppreference.com/w/cpp/header
  • @RichardCritten Oh !@#$^% -- 这太疯狂了。有什么办法吗?
  • @bitmask: 将你的命名空间命名为其他名称,或者将其包装在另一个命名空间中?

标签: c++ namespaces std


【解决方案1】:

为什么&lt;cmath&gt; 会暴露 std 命名空间之外的实体?

因为历史。

&lt;cmath&gt; 标头是从 C 标准库继承的标头(命名为 &lt;math.h&gt;)。在 C 语言中,只有全局命名空间1 声明了所有名称。

由于许多 C++ 实现也是 C 实现,因此它们通常通过按原样包含它来实现继承的 C 标准头文件2,这意味着它声明了全局名称。

虽然可能有一些技术可以避免(标准宏除外)声明全局名称,但自标准化之前就一直在这样做的实现不太可能改变行为,因为这会破坏向后兼容性。

我的标准库坏了吗?

没有。 C++ 标准允许这样做;所有 C 标准库名称都保留供语言实现使用。你不能自己定义它们。

我可以做些什么来避免这种情况吗?

您通常无法阻止标准库执行此操作。

您可以通过选择使用独立的语言实现在技术上避免大部分情况。但是如果你选择它,你将失去几乎整个标准库。

您可以通过避免自己声明任何全局名称来最大程度地减少名称冲突的可能性,但具有足够唯一名称的单个命名空间除外。比如:

namespace usr_bitmask::log {

}

1 请注意,C 语言中的“命名空间”概念是另外一回事。

2 此外,在使用 &lt;c... 命名标头时重新声明 std 命名空间中的名称,并在某些情况下添加特定于 C++ 的重载。

【讨论】:

【解决方案2】:

也许有更多 C/C++ 标准知识的人会证明我错了,但是对于一个 C++ 编译器也能够处理 C 代码,来自 C 库的函数需要在命名空间之外,事实上你应该只是找到包含在 extern "C" 中的 C-Library 定义,这样您就可以透明地使用 C++ 代码中的旧 C 函数

【讨论】:

  • C 代码不会包含cmath,而是包含math.h
  • 当然可以,但是当您在 C++ 项目中包含 C 代码 sn-p 时,通常包含 cmath,而不是 math.h
猜你喜欢
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-25
  • 1970-01-01
  • 2018-12-25
  • 2018-11-27
  • 1970-01-01
相关资源
最近更新 更多