На самом деле у вас есть почти все, что вам нужно, но вы все еще используете обычный класс с конкретным типом.
using Item = std::string;
class DList { ... };
Итак, сначала мы отбрасываем конкретный тип:
// using Item = std::string;
class DList { ... }; // sure Item is now undefined...
Затем мы говорим, что класс должен быть шаблоном
template <typename Item>
class DList { ... };
Теперь Item
вновь введен, но вместо того, чтобы быть конкретным типом, теперь он является универсальным. Вот и все, у вас есть список шаблонов (при условии, что список реализован правильно, я не проверял).
Всякий раз, когда вы сейчас создаете экземпляр своего списка:
DList<int>;
DList<std::string>;
// ...
Вы создаете совершенно новыйнезависимый тип данных (это означает, в частности, что вы не можете назначить DList<int>
для указателя на DList<double>
, просто все так же, как вы не можете назначить int для указателя, чтобы удвоить либо).
Когда выПри создании экземпляра шаблона каждый экземпляр параметра шаблона будет заменен типом, с которым вы создали экземпляр шаблона, например, в DList<int>
, каждый случай Item
будет заменен на int
.
Ну,все это просто очень краткое введение, еще много чего нужно сделать, но это скорее будет рассмотрено в книге, чем в ответе на stackoverflow ...
Хотя некоторые примечания для конструктора вашего узла:
DListNode(Item i /* , ... */) { item = i; }
Сначала вы должны привыкнуть к использованию списка инициализатора конструктора (не путать с std::initializer_list
):
DListNode(Item i /* , ... */) : item(i) { }
Вы избегаете стандартных инициализацийДействие + присваивание в пользу прямой инициализации по значению. Кроме того, некоторые типы (не конструируемые по умолчанию, константы и ссылки) только могут быть инициализированы таким образом.
Затем вы создаете ненужную копию:
DListNode(Item i /* , ... */) : item(i) { }
// ^ temporary copy ^ final copy, created from temporary
Вы избегаете этой копии, если принимаете элемент по ссылке:
DListNode(Item const& i /* , ... */) : item(i) { }
// now copies from reference, one copy less
Вы можете дополнительно указать семантику перемещения:
DListNode(Item&& i /* , ... */) : item(std::move(i)) { }
, чтобы объекты, которые вам не нужны, находились внеСписок больше можно перенести в (ну собственно их содержимое). В некоторых случаях это может быть намного дешевле, чем полная копия ...
Все сказанное о конструкторе (кроме списка инициализатора) относится и к функциям append
и insertAfter
.
Списки инициализаторов и избегание копий - это общий совет, не связанный с шаблонами ...