C++模板特化如何使用默认布尔值工作?

huangapple go评论70阅读模式
英文:

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 &lt;class _Tp, class _Alloc,
          class _RawAlloc = __libcpp_remove_reference_t&lt;_Alloc&gt;,
          bool = __has_pointer&lt;_RawAlloc&gt;::value&gt;
struct __pointer {
    using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
};
template &lt;class _Tp, class _Alloc, class _RawAlloc&gt;
struct __pointer&lt;_Tp, _Alloc, _RawAlloc, false&gt; {
    using type _LIBCPP_NODEBUG = _Tp*;
};

What puzzled me is this line:

bool = __has_pointer&lt;_RawAlloc&gt;::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&lt;_RawAlloc&gt;::value&gt; 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 &lt;class _Tp, class = void&gt; struct NAME : false_type { };    \
template &lt;class _Tp&gt;               struct NAME&lt;_Tp, __void_t&lt;typename _Tp:: PROPERTY &gt; &gt; : true_type { }

答案1

得分: 2

> 不应该在第一个实例的模板参数中显式使用 true,然后模板专门化生效吗?

首先,你定义一个模板。这个“基础”模板是你尝试实例化模板时得到的结果。

然后,你可以定义一个专门化。如果模板参数与专门化的匹配,你就得到了专门化的模板。惊喜!

让我们忽略专门化。没有专门化的情况下,这就是在实例化此模板时得到的模板。这就是在最后一个模板参数为 truefalse 时得到的模板。不管怎样,这就是你的模板。享受吧。祝你好胃口。

但等等,你忘了:你还有一个专门化。慢下来:如果最后一个模板参数为 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 &lt;class _Tp, class _Alloc,
          class _RawAlloc = __libcpp_remove_reference_t&lt;_Alloc&gt;,
          bool = __has_pointer&lt;_RawAlloc&gt;::value&gt;
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 &lt;class _Tp, class _Alloc,
          class _RawAlloc = __libcpp_remove_reference_t&lt;_Alloc&gt;,
          bool = __has_pointer&lt;_RawAlloc&gt;::value&gt;
struct __pointer;

template &lt;class _Tp, class _Alloc, class _RawAlloc&gt;
struct __pointer&lt;_Tp, _Alloc, _RawAlloc, true&gt; {
    using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
};

template &lt;class _Tp, class _Alloc, class _RawAlloc&gt;
struct __pointer&lt;_Tp, _Alloc, _RawAlloc, false&gt; {
    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 &lt;class _Tp, class _Alloc,
          class _RawAlloc = __libcpp_remove_reference_t&lt;_Alloc&gt;,
          bool = __has_pointer&lt;_RawAlloc&gt;::value&gt;
struct __pointer {
    using type _LIBCPP_NODEBUG = typename _RawAlloc::pointer;
};

A primary class template is defined and the bool = __has_pointer&lt;_RawAlloc&gt;::value part of the template is a bool non-type tmplate parameter that is defaulted to the value of __has_pointer&lt;_RawAlloc&gt;::value. __has_pointer&lt;_RawAlloc&gt;::value will return true if _RawAlloc has a pointer member and false otherwise.

Next we have

template &lt;class _Tp, class _Alloc, class _RawAlloc&gt;
struct __pointer&lt;_Tp, _Alloc, _RawAlloc, false&gt; {
    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

huangapple
  • 本文由 发表于 2023年4月17日 07:57:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76030905.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定