关于 C++ 的问题模板语法(STL库源代码)

发布于 2024-08-07 17:42:17 字数 581 浏览 1 评论 0原文

我现在正在阅读STL源代码。 虽然我理解我在 stl_list.h 中阅读的内容,但我想完全理解以下代码片段(我认为主要与模板语法相关)。

template

class _List_base {
  ...
  typedef typename _Alloc::template rebind<_List_node<_Tp> >::other _Node_Alloc_type; //(1).

  ...
  typedef _Alloc allocator_type;
  get_allocator() const
  { return allocator_type(*static_cast<
                          const _Node_Alloc_type*>(&this->_M_impl)); }  // (2)
  ...
};

有人能解释一下为什么我们在第 (1) 行的 _Alloc 之后需要一个“模板”吗? (并给出这一行的完整解释?)

有人可以解释为什么我们可以在第(2)行中将 _Node_Alloc_type 转换为 _Alloc 吗?

I am reading STL source code right now.
Though I understand the meat in what I am reading in stl_list.h, I want to fully understand the following snippet (mainly related to the template syntax, I think).

template

class _List_base {
  ...
  typedef typename _Alloc::template rebind<_List_node<_Tp> >::other _Node_Alloc_type; //(1).

  ...
  typedef _Alloc allocator_type;
  get_allocator() const
  { return allocator_type(*static_cast<
                          const _Node_Alloc_type*>(&this->_M_impl)); }  // (2)
  ...
};

Can someone explain why we need a "template" following _Alloc in line (1)? (and giving a full explanation of this line?)

Can someone explain why we can cast _Node_Alloc_type to _Alloc in line (2)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

居里长安 2024-08-14 17:42:17

需要 template 关键字将名称 rebind 标识为类模板。如果没有它,rebind 可以被视为变量或常量(在本例中是由于 typename 关键字而产生的类型)以及以下 <可以被解释为小于运算符。

这有点类似于 typename 关键字(这当然是将 other 识别为类型所必需的)。

每个分配器都需要提供一个名为“rebind”的元函数(即类模板),它返回相同的分配器,但类型不同。换句话说,

Alloc<T>::rebind<U>::other

在没有更多上下文的情况下,将与问题的第二部分命名相同的类型

Alloc<U>

很难回答。 _M_impl 的类型是什么?该类型是如何定义的?

The template keyword is needed to identify the name rebind as a class template. Without it, rebind could be considered a variable or a constant (in this case a type due to the typename keyword) and the following < could be interpreted as a less-than operator.

This is somewhat similar to the typename keyword (which is of course necessary to identify other as a type).

Every allocator is required to provide a meta-function (i.e. a class template) called rebind that returns the same allocator but for a different type. In other words,

Alloc<T>::rebind<U>::other

names the same type as

Alloc<U>

The second part of your question is difficult to answer without more context. What is the type of _M_impl? How is that type defined?

清眉祭 2024-08-14 17:42:17

它看起来像 std::list 的 gcc 实现。在这种情况下,上下文是:

struct _List_impl : public _Node_Alloc_type { ... };
_List_impl _M_impl;

并且你忘记写成员函数的返回类型:

typedef _Alloc allocator_type;
allocator_type
get_allocator() const
{ return allocator_type(*static_cast<const _Node_Alloc_type*>(&this->_M_impl)); }

回答(1)

当在_Tp类型的列表中添加节点时,真正需要分配的是什么不是对象_Tp,而是包含_Tp的列表节点(_List_node<_Tp>)。

因此 std::list 需要能够分配 _List_node<_Tp>,但它已为 _Tp 提供了分配器。这就是模板 typedef rebind 派上用场的地方:它使得可以从类型 T 的分配器中获取类型 U 的分配器。

使用此重新绑定,我们得到一个 _Alloc<_List_node<_Tp>; > 来自类型 _Alloc<_Tp>


源文件中对 (2) 的回答作为注释:

// NOTA BENE
// The stored instance is not actually of "allocator_type"'s
// type.  Instead we rebind the type to
// Allocator<List_node<Tp>>, which according to [20.1.5]/4
// should probably be the same.  List_node<Tp> is not the same
// size as Tp (it's two pointers larger), and specializations on
// Tp may go unused because List_node<Tp> is being bound
// instead.
//
// We put this to the test in the constructors and in
// get_allocator, where we use conversions between
// allocator_type and _Node_Alloc_type. The conversion is
// required by table 32 in [20.1.5].

假设 _Alloc 的类型与 C++ 标准中的 _Node_Alloc_type 相同;因此 static_cast 断言转换是合法的。

It looks like the gcc implementation of std::list. In that case, the context is:

struct _List_impl : public _Node_Alloc_type { ... };
_List_impl _M_impl;

And you forgot to write the return type of the member function:

typedef _Alloc allocator_type;
allocator_type
get_allocator() const
{ return allocator_type(*static_cast<const _Node_Alloc_type*>(&this->_M_impl)); }

Answer for (1)

When adding a node in a list of type _Tp, what really needs to be allocated is not an object _Tp but a list node containing _Tp (a _List_node<_Tp>).

So the std::list needs to be able allocate a _List_node<_Tp> but it has been provided an allocator for _Tp. This is where the template typedef rebind comes in handy: it makes it possible to get an allocator for type U from an allocator for type T.

Using this rebind, we get an _Alloc<_List_node<_Tp> > from the type _Alloc<_Tp>.


Answer for (2) in the source file as comment:

// NOTA BENE
// The stored instance is not actually of "allocator_type"'s
// type.  Instead we rebind the type to
// Allocator<List_node<Tp>>, which according to [20.1.5]/4
// should probably be the same.  List_node<Tp> is not the same
// size as Tp (it's two pointers larger), and specializations on
// Tp may go unused because List_node<Tp> is being bound
// instead.
//
// We put this to the test in the constructors and in
// get_allocator, where we use conversions between
// allocator_type and _Node_Alloc_type. The conversion is
// required by table 32 in [20.1.5].

It is assumed that _Alloc's type is the same as _Node_Alloc_type as per the C++ Standard; hence the static_cast asserts the conversion is legal.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文