我正在查看 libc++ 的代码,我注意到了这个片段:
// __pointer
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(__has_pointer, pointer);
template <class _Tp, class _Alloc,
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
bool = __has_pointer<_RawAlloc>::value>
struct __pointer {
using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
};
template <class _Tp, class _Alloc, class _RawAlloc>
struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
using type _LIBCPP_NODEBUG = _Tp*;
};
让我疑惑的是这一行:
bool = __has_pointer<_RawAlloc>::value
这段代码的语义非常清楚:这里我们调用一个元函数
__has_pointer
,如果它为真,我们就使用__pointer
的第一个实现,如果不是,我们就使用第二个(显式为假的那个)在其模板参数中)。我很困惑,因为我不明白这是如何工作的,第一个实例不应该在其模板参数中有一个明确的true
然后模板专业化开始吗?如果是这样,那么我们需要在启动此模板时调用元函数,所以也许bool = __has_pointer<_RawAlloc>::value>
是它的简写?我想知道这里使用了什么样的机制才能允许这样做。用于使这项工作的规则是什么?
_LIBCPP_ALLOCATOR_TRAITS_HAS_XXX
的完整实现可以在这里找到:
#define _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX(NAME, PROPERTY) \
template <class _Tp, class = void> struct NAME : false_type { }; \
template <class _Tp> struct NAME<_Tp, __void_t<typename _Tp:: PROPERTY > > : true_type { }
第一个实例不应该在其模板参数中有一个明确的 true 然后模板专业化开始吗?
首先,您定义一个模板。如果您尝试实例化一个模板,就会得到这个“基本”模板。
然后你可以定义一个专业化。如果模板参数与专业化匹配,那么您将获得专业化模板。惊喜!
template <class _Tp, class _Alloc,
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
bool = __has_pointer<_RawAlloc>::value>
struct __pointer
让我们忽略专业化。如果没有专门化,这是您在实例化此模板时将获得的模板。这就是当最后一个模板参数是
true
或 false
时得到的结果。没关系。这是你的模板。好好享受。祝你胃口好
但是等等,你忘了:你也有专长。别急:如果最后一个模板参数是
false
,你的餐点就是专业化。
但是,如果最后一个模板参数原来是
true
没有任何变化,你仍然得到原始模板。其他地方都不需要设置为“显式真实”。
话虽如此,是的,您实际上可以通过 two 专业化,甚至不定义基本模板,使事情看起来像这样:
template <class _Tp, class _Alloc,
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
bool = __has_pointer<_RawAlloc>::value>
struct __pointer;
template <class _Tp, class _Alloc, class _RawAlloc>
struct __pointer<_Tp, _Alloc, _RawAlloc, true> {
using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
};
template <class _Tp, class _Alloc, class _RawAlloc>
struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
using type _LIBCPP_NODEBUG = _Tp*;
};
这在逻辑上是等价的。这两种选择在逻辑上是等价的。
这只是一个类型特征,用于使用类的部分专业化 分派到特定的实现。有
template <class _Tp, class _Alloc,
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
bool = __has_pointer<_RawAlloc>::value>
struct __pointer {
using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
};
定义了一个初级类模板,模板的
bool = __has_pointer<_RawAlloc>::value
部分是一个bool
非类型tmplate参数,默认为__has_pointer<_RawAlloc>::value
的值。 __has_pointer<_RawAlloc>::value
将返回 true
如果 _RawAlloc
有一个 pointer
成员和 false
否则。
接下来我们有
template <class _Tp, class _Alloc, class _RawAlloc>
struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
using type _LIBCPP_NODEBUG = _Tp*;
};
这是主模板的偏特化,只要最后一个模板参数是
false
.就会被使用
这意味着当
_RawAlloc
有 pointer
成员时使用主模板,而当它没有时使用专业化