为什么标准库类型可以访问在“std”中,尽管它们嵌套在实现定义的命名空间中?

Why are standard library types accessible inside `std` despite being nested in implementation-defined namespaces?

提问人:md1357 提问时间:3/25/2022 更新时间:12/21/2022 访问量:279

问:

我正在浏览 GCC 11.2 标头的实现(可以在这里找到),我注意到一些我正在努力理解的东西。这是标题(希望)只遗漏了重要的部分:<optional>

#ifndef _GLIBCXX_OPTIONAL
#define _GLIBCXX_OPTIONAL 1

#pragma GCC system_header

#if __cplusplus >= 201703L

/* Includes of various internal and library headers */

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

#if __cplusplus == 201703L
# define __cpp_lib_optional 201606L
#else
# define __cpp_lib_optional 202106L
#endif

  /* Implementation */

  template<typename _Tp>
  class optional;

  /* Implementation */

  template<typename _Tp>
  class optional: /* Implementation */
  { /* Implementation */ };

  /* Implementation */


_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif // C++17

#endif // _GLIBCXX_OPTIONAL

我发现并分别扩展到 和 (之前没有)。_GLIBCXX_BEGIN_NAMESPACE_VERSION_GLIBCXX_END_NAMESPACE_VERSIONnamespace __8 {}inlinenamespace __8

因此,它看起来实际上是在非内联命名空间中定义的,但尽管如此,我显然可以在我的程序中引用,就好像它直接位于 .std::optionalstd::__8std::optionalstd

我认为没有任何有效的指令,首先是因为我没有找到任何指令,其次是因为应该允许它专门用于自定义类型,而无需打开实现定义的命名空间([namespace.std#2],[temp.spec.partial.general#6])。usingstd::optional

宏扩展到 ,但我认为它不相关(文档)。我在文档的编译指示列表中找不到。_GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))system_header

因此,我不明白为什么我应该能够引用可选类 as 和 not .我在这里错过了什么?std::optionalstd::__8::optional

C++ 命名空间 语言律师 20 C+ +标准库

评论

2赞 StoryTeller - Unslander Monica 3/25/2022
只有第一个声明需要内联说明符 wandbox.org/permlink/KGbd6EWKRvyhbNLL

答:

9赞 Barry 3/25/2022 #1

定义这些宏的 in libstdc++ 最初也声明了 version 命名空间,如下所示c++configinline

// Defined if inline namespaces are used for versioning.
#define _GLIBCXX_INLINE_VERSION 

// Inline namespace for symbol versioning.
#if _GLIBCXX_INLINE_VERSION
# define _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __8 {
# define _GLIBCXX_END_NAMESPACE_VERSION }

namespace std
{
inline _GLIBCXX_BEGIN_NAMESPACE_VERSION
#if __cplusplus >= 201402L
  inline namespace literals {
    inline namespace chrono_literals { }
    inline namespace complex_literals { }
    inline namespace string_literals { }
#if __cplusplus > 201402L
    inline namespace string_view_literals { }
#endif // C++17
  }
#endif // C++14
_GLIBCXX_END_NAMESPACE_VERSION
}

一旦 a 被声明,它总是 .例如:namespaceinlineinline

namespace A {
  inline namespace B {
    struct X { };
  }
}

namespace A {
  namespace B {
    struct Y { };
  }
}

A::X x; // ok
A::Y y; // still ok

即使 GCC 没有,Clang 也警告了这一点,但它也是一个系统标头,所以即使 GCC 对它有所影响也没关系。

不过,不知道为什么不直接添加到宏定义中。我们可能还没有到每个标头额外的 7 个字符对编译时间造成重大损害的地步?inline

评论

0赞 user2023370 12/21/2022
很有帮助,谢谢。文件名不是?c++configconfig.h
0赞 user2023370 12/21/2022
类似的东西在用户代码中有效吗?(不管它的用处如何。std::__8::vector