我想看看C ++矢量是如何制作的。我找到了这个, 实现是LLVM编译器https://llvm.org/svn/llvm-project/libcxx/trunk/src/vector.cpp appleclang
的src / vector.cpp:
#include "vector"
_LIBCPP_BEGIN_NAMESPACE_STD
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD
实施https://llvm.org/svn/llvm-project/libcxx/trunk/include/vector appleclang LLVM。
包括/矢量:
// .. deleted code
template <bool>
class __vector_base_common
{
protected:
_LIBCPP_ALWAYS_INLINE __vector_base_common() {}
_LIBCPP_NORETURN void __throw_length_error() const;
_LIBCPP_NORETURN void __throw_out_of_range() const;
};
template <bool __b>
void
__vector_base_common<__b>::__throw_length_error() const
{
_VSTD::__throw_length_error("vector");
}
template <bool __b>
void
__vector_base_common<__b>::__throw_out_of_range() const
{
_VSTD::__throw_out_of_range("vector");
}
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __vector_base_common<true>)
// .. deleted code
template <class _Tp, class _Allocator>
class __vector_base
: protected __vector_base_common<true>
// .. deleted code
class _LIBCPP_TEMPLATE_VIS vector
: private __vector_base<_Tp, _Allocator>
// .. deleted code
我有很多问题如何制作一个向量...甚至要问一个人感到很尴尬但是..为什么__vector_base_common采用bool模板参数?它似乎没有使用它,我验证只在代码__vector_base_common<true>
中使用,false
值未使用。
编辑:有关vector<bool>
的多个建议。仅使用上述bool参数的一个特化(true
)。这就是矢量特殊的样子
template <class _Allocator>
class _LIBCPP_TEMPLATE_VIS vector<bool, _Allocator>
: private __vector_base_common<true>
私有与受保护之间存在差异......这是不需要那些抛出成员函数的向量的空间优化吗?我仍然怀疑为什么__vector_base_common
需要模板参数。这个C ++模式是否具有名称?
答案 0 :(得分:2)
这是一个实现技巧,因此库既可以用作标题,也可以使用预编译的部分。
vector
的一些成员函数根本不依赖于模板参数;特别是,抛出异常的辅助函数。因此,可以(与依赖于模板参数的部分不同)将它们编译一次并将它们放在共享库中。例如,这就是在MacOS上发生的事情。
另一方面,在没有与OS一起分发库的平台上,如果用户不必分发共享库,则可以更方便用户,但可以将库作为仅头文件使用,即包括<vector>
并完成它,而不必在构建中向链接器调用添加标志。
这意味着您需要在标头中提供这些函数的代码,但是如果您使用共享库变体,则在使用标头时实际上不应该编译它。
这里介绍的技巧是实现这一目标的一种方法。首先,将实现放入模板中,以便它可以存在于标题中而不会产生多个定义错误。有问题的模板只有一个虚拟参数;重要的是它是一个模板,而不是它有任何特定的参数。这是仅限标头库使用的常用技术。
现在您可以使用库标头了。但是,如果要使用共享库变体,实际上需要提前编译代码并禁止库用户生成代码。可以使用显式模板实例化。
所以你在标题中放了一个extern模板声明:
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __vector_base_common<true>;
因此标题现在包含一个显式的特化声明,禁止模板成员的代码生成。
然后你获取一个源文件,放入显式实例化,并将其编译为共享库。
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
现在您已经涵盖了共享库使用,但是您破坏了仅使用库头的功能。为了实现这一点,您需要使extern template
声明可选,具体取决于库的使用模式。因此,您将声明包装在宏中,其定义取决于模式:
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS __vector_base_common<true>)
#ifdef _LIBCPP_DISABLE_EXTERN_TEMPLATE
#define _LIBCPP_EXTERN_TEMPLATE(...)
#endif
#ifndef _LIBCPP_EXTERN_TEMPLATE
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
#endif
因此,如果您处于仅标头模式(_LIBCPP_DISABLE_EXTERN_TEMPLATE
已定义),则声明将消失。如果您处于共享库模式,则声明存在,从而阻止了代码生成。
vector<bool>
私有地从__vector_base_common
派生的原因是因为它本身没有任何需要访问throw助手的派生类。 vector<T>
来自__vector_base<T>
,__vector_base<T>
来自__vector_base_common
;因此,vector<T>
要__vector_base_common
成员有__vector_base<T>
成员,__vector_base_common
必须来自protected
{{1}}。