尽管标准库类型嵌套在 implementation-defined 命名空间中,但为什么可以在 `std` 中访问标准库类型?
Why are standard library types accessible inside `std` despite being nested in implementation-defined namespaces?
我正在浏览 GCC 11.2 的 <optional>
header 的实现(可以找到 here),我注意到一些我难以理解的东西。这是 header,(希望如此)只遗漏了重要的部分:
#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_VERSION
分别扩展为namespace __8 {
和}
(namespace __8
之前没有inline
)。
因此,看起来 std::optional
实际上是在 non-inline 命名空间 std::__8
中定义的,但尽管如此,我显然可以在我的程序中引用 std::optional
,就好像它直接位于 std
.
内
我认为没有任何有效的 using
指令,首先是因为我还没有找到任何指令,其次是因为应该允许它在不打开的情况下专门针对自定义类型 std::optional
implementation-defined 个命名空间 ([namespace.std#2], [temp.spec.partial.general#6])。
_GLIBCXX_VISIBILITY(default)
宏扩展为 __attribute__ ((__visibility__ ("default")))
,但我认为它不相关 (documentation)。我在文档的编译指示列表中找不到 system_header
。
因此,我不明白为什么我应该能够将可选的 class 引用为 std::optional
而不是 std::__8::optional
。我在这里错过了什么?
定义这些宏的libstdc++中的config.h
最初也将版本命名空间声明为inline
here:
// 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
}
一旦 namespace
被声明 inline
,它总是 inline
。例如:
namespace A {
inline namespace B {
struct X { };
}
}
namespace A {
namespace B {
struct Y { };
}
}
A::X x; // ok
A::Y y; // still ok
clang 对此发出警告,即使 gcc 没有警告,但它也是一个系统 header 所以即使 gcc 警告它也没关系。
仍然不确定为什么不直接将 inline
添加到宏定义中。我们可能还没有达到每个 header 额外的 7 个字符对编译时间造成重大损害的地步?
我正在浏览 GCC 11.2 的 <optional>
header 的实现(可以找到 here),我注意到一些我难以理解的东西。这是 header,(希望如此)只遗漏了重要的部分:
#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_VERSION
分别扩展为namespace __8 {
和}
(namespace __8
之前没有inline
)。
因此,看起来 std::optional
实际上是在 non-inline 命名空间 std::__8
中定义的,但尽管如此,我显然可以在我的程序中引用 std::optional
,就好像它直接位于 std
.
我认为没有任何有效的 using
指令,首先是因为我还没有找到任何指令,其次是因为应该允许它在不打开的情况下专门针对自定义类型 std::optional
implementation-defined 个命名空间 ([namespace.std#2], [temp.spec.partial.general#6])。
_GLIBCXX_VISIBILITY(default)
宏扩展为 __attribute__ ((__visibility__ ("default")))
,但我认为它不相关 (documentation)。我在文档的编译指示列表中找不到 system_header
。
因此,我不明白为什么我应该能够将可选的 class 引用为 std::optional
而不是 std::__8::optional
。我在这里错过了什么?
定义这些宏的libstdc++中的config.h
最初也将版本命名空间声明为inline
here:
// 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
}
一旦 namespace
被声明 inline
,它总是 inline
。例如:
namespace A {
inline namespace B {
struct X { };
}
}
namespace A {
namespace B {
struct Y { };
}
}
A::X x; // ok
A::Y y; // still ok
clang 对此发出警告,即使 gcc 没有警告,但它也是一个系统 header 所以即使 gcc 警告它也没关系。
仍然不确定为什么不直接将 inline
添加到宏定义中。我们可能还没有达到每个 header 额外的 7 个字符对编译时间造成重大损害的地步?