Вопрос о синтаксисе шаблона C ++ (исходный код библиотеки STL) - PullRequest
5 голосов
/ 12 октября 2009

Я сейчас читаю исходный код STL. Хотя я понимаю смысл того, что я читаю в stl_list.h, я хочу полностью понять следующий фрагмент (я думаю, в основном это касается синтаксиса шаблона).

шаблон

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)
  ...
};

Может кто-нибудь объяснить, почему нам нужен «шаблон», следующий за _Alloc в строке (1)? (и дать полное объяснение этой строки?)

Может кто-нибудь объяснить, почему мы можем привести _Node_Alloc_type к _Alloc в строке (2)?

Ответы [ 2 ]

12 голосов
/ 12 октября 2009

Ключевое слово template необходимо для идентификации имени rebind в качестве шаблона класса. Без этого rebind можно было бы считать переменной или константой (в данном случае это тип из-за ключевого слова typename), а следующий < мог бы быть интерпретирован как оператор меньше чем.

Это несколько похоже на ключевое слово typename (которое, конечно же, необходимо для определения other как типа).

Каждый распределитель должен предоставлять мета-функцию (то есть шаблон класса) с именем rebind, которая возвращает тот же распределитель, но для другого типа. Другими словами,

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

именует тот же тип, что и

Alloc<U>

На вторую часть вашего вопроса трудно ответить без дополнительного контекста. Какой тип _M_impl? Как определяется этот тип?

2 голосов
/ 13 октября 2009

Похоже, что gcc-реализация std :: list. В этом случае контекст таков:

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 (a _List_node<_Tp>).

Таким образом, std :: list должен иметь возможность выделять _List_node<_Tp>, но ему был предоставлен распределитель для _Tp. Вот где шаблон typedef rebind пригодится: он позволяет получить распределитель для типа U от распределителя для типа T.

Используя эту привязку, мы получаем _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 совпадает с _Node_Alloc_type в соответствии со стандартом C ++; следовательно static_cast утверждает, что преобразование допустимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...