英文:
How does C++ template specialization work with default boolean value?
问题
bool = __has_pointer<_RawAlloc>::value
翻译为:
bool = __has_pointer<_RawAlloc>::value
英文:
I am looking through libc++'s code and I have noticed this snippet:
// __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*;
};
What puzzled me is this line:
bool = __has_pointer<_RawAlloc>::value
The semantics of this code are pretty clear: here we call a metafunction __has_pointer
and if it is true, we go with the first implementation of __pointer
and if it's not we go with the second (the one with an explicit false in its template parameter). I am confused because I don't understand how this works, shouldn't the first instance have an explicit true
in its template params and then template specialization kicks in? If that's the case then we need to call the metafunction when we initiate this template, so maybe bool = __has_pointer<_RawAlloc>::value>
is a shorthand for that? I am wondering what kind of mechanism is used here so that this is allowed. What are the rules that are used to make this work?
Full implementation of _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX
can be found here:
#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 { }
答案1
得分: 2
> 不应该在第一个实例的模板参数中显式使用 true,然后模板专门化生效吗?
首先,你定义一个模板。这个“基础”模板是你尝试实例化模板时得到的结果。
然后,你可以定义一个专门化。如果模板参数与专门化的匹配,你就得到了专门化的模板。惊喜!
让我们忽略专门化。没有专门化的情况下,这就是在实例化此模板时得到的模板。这就是在最后一个模板参数为 true
或 false
时得到的模板。不管怎样,这就是你的模板。享受吧。祝你好胃口。
但等等,你忘了:你还有一个专门化。慢下来:如果最后一个模板参数为 false
,那么你的餐点将是专门化的。
然而,如果最后一个模板参数为 true
,什么都不会改变,你仍然得到原始模板。不需要在其他地方设置为“显式 true”。
话虽如此,是的,你实际上可以通过有两个专门化而不定义基础模板使事情看起来这样:
// (代码部分不翻译)
这在逻辑上是等效的。这两种替代方案在逻辑上是相互等效的。
英文:
> Shouldn't the first instance has an explicit true in its template params and then template specialization kicks in?
First, you define a template. This "base" template is what you get if you attempt to instantiate a template.
Then you get to define a specialization. If the template parameters match the specialization's then you get the specialized template. Surprise!
template <class _Tp, class _Alloc,
class _RawAlloc = __libcpp_remove_reference_t<_Alloc>,
bool = __has_pointer<_RawAlloc>::value>
struct __pointer
Let's ignore the specialization. Without the specialization this is the template you'll get when you instantiate this template. This is what you get when the last template parameter turns out to be either true
, or false
. It doesn't matter. This is your template. Enjoy it. Bon appetit.
But wait, you forgot: you also have a specialization. Hold your horses: if the last template parameter turns out to be false
, your meal will be the specialization.
However, if the last template parameter turns out to be true
nothing changes, you still get the original template. Nothing needs to be set to an "explicit true" elsewhere.
Having said that, yes, you can actually make things look this way, by having two specializations, and not even defining the base template:
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*;
};
This is logically equivalent. Both alternatives are logically equivalent to each other.
答案2
得分: 2
这只是一个类型特性,用于使用类的部分特化来调度到特定实现。使用以下代码片段:
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
非类型模板参数,其默认值为 __has_pointer<_RawAlloc>::value
的值。如果 _RawAlloc
有一个 pointer
成员,__has_pointer<_RawAlloc>::value
将返回 true
,否则返回 false
。
接下来我们有:
template <class _Tp, class _Alloc, class _RawAlloc>
struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
using type _LIBCPP_NODEBUG = _Tp*;
};
这是主模板的部分特化,将在最后一个模板参数为 false
时使用。
这意味着当 _RawAlloc
有一个 pointer
成员时,将使用主模板,而当它没有时,将使用特化模板。
英文:
This is just a type trait being used to dispatch to a particular implementation using partial specialization of the class. With
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;
};
A primary class template is defined and the bool = __has_pointer<_RawAlloc>::value
part of the template is a bool
non-type tmplate parameter that is defaulted to the value of __has_pointer<_RawAlloc>::value
. __has_pointer<_RawAlloc>::value
will return true
if _RawAlloc
has a pointer
member and false
otherwise.
Next we have
template <class _Tp, class _Alloc, class _RawAlloc>
struct __pointer<_Tp, _Alloc, _RawAlloc, false> {
using type _LIBCPP_NODEBUG = _Tp*;
};
which is the partial specialization of the primary template and will be used whenever the last template parameter is false
.
This means the primary template is used when _RawAlloc
has a pointer
member and the specialization when it does not
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论