Почему псевдоним параметра шаблона в стандартных контейнерах С++?

Просматривая код Microsoft STL (в частности, std::vector), я наткнулся на следующие строки кода (нерелевантный код заменен на /* ... */):

// CLASS TEMPLATE vector
template <class _Ty, class _Alloc = allocator<_Ty>>
class vector // varying size array of values
{ 
    /* ... */
public:

   /* ... */
   using value_type = _Ty;
   using allocator_type = _Alloc;
   using pointer = typename _Alty_traits::pointer;
   using const_pointer = typename _Alty_traits::const_pointer;
   using reference = _Ty&;
   using const_reference = const _Ty&;
   using size_type = typename _Alty_traits::size_type;
   using difference_type = typename _Alty_traits::difference_type;
   /* ... */
};

Мне было интересно, почему здесь используется соглашение о присвоении псевдонима типа типу шаблона?


person Drake Johnson    schedule 26.07.2020    source источник
comment
Мне было интересно, почему здесь используется соглашение о присвоении псевдонима типа типу шаблона? - Для окончательного ответа вам нужно спросить людей Microsoft, которые написали этот код. Но моя догадка заключается в том, что это сделано для того, чтобы сделать код более читабельным. Кроме того, некоторые из этих имен указаны в стандарте, поэтому они должны их предоставлять, но для типов шаблонов они должны использовать зарезервированные имена, такие как _Foo.   -  person Jesper Juhl    schedule 26.07.2020
comment
Кажется, это дубликат stackoverflow.com/questions/44571362/   -  person ony    schedule 26.07.2020


Ответы (4)


Мне было интересно, почему здесь используется соглашение о присвоении псевдонима типа типу шаблона?

Потому что это так

  • стандартный способ сделать,
  • делает код менее подверженным ошибкам,
  • меньше печатать,
  • более читаемый и
  • все вышеперечисленное облегчает жизнь!

Например, рассмотрим const_pointer, общедоступный псевдоним шаблона std::vector.

using const_pointer   = typename _Alty_traits::const_pointer;

В какой-то момент вы захотите узнать этот тип и использовать его в функции, как это было бы возможно без вышеуказанного псевдонима?

Конечно, вы можете написать

#include <memory> // std::allocator_traits

using const_pointer = typename std::allocator_traits<typename std::vector</*type*/>::allocator_type>::const_pointer;

в любом месте вашей программы. Но это приводит к более подверженным ошибкам ситуациям (например, отсутствие некоторых typename и т. д.) и большему количеству ввода.

Поэтому имеет смысл собирать такие типы контейнера и предоставлять общедоступные типы-псевдонимы.

person JeJo    schedule 26.07.2020

Мне было интересно, почему здесь используется соглашение о присвоении псевдонима типа типу шаблона?

Предположим, у вас есть шаблонная функция, которая принимает контейнер STL (std::vector, std::deque, std::set, std::multi_set,...)

template <typename T>
void foo (T const & t)
 {
   // ...
 }

и что вам нужен тип содержащихся значений.

Вы можете внутри foo() просто написать

 using needed_type = typename T::value_type;

и это работает для std::vector, std::deque, std::set, std::multi_set, std::array, std::map, std::multi_map и т. д.

person max66    schedule 26.07.2020
comment
То есть они, по сути, стандартизируют способ доступа к типам параметров шаблона за пределами самого определения класса? - person Drake Johnson; 26.07.2020

Это соглашение фактически использовалось для предоставления трейтов. Именование этих типов следует некоторому соглашению, позволяющему писать такие функции, как distance, в терминах эти черты и заставить его работать для многих контейнеров.

И я почти уверен, что наличие этих типов для стандартной библиотеки C++ является частью спецификации, и они должны были ее придерживаться.

person ony    schedule 26.07.2020

Стандарт С++ требует, чтобы std::vector предоставлял двойную горсть вложенных имен, и это те, о которых задается вопрос. Вот почему есть value_type, allocator_type, pointer и т. д. Вы можете использовать эти имена в своем коде, когда вам нужны типы, на которые они ссылаются. Например, нередко можно увидеть std::vector<int>::iterator в пользовательском коде для обозначения типа итератора, который предоставляет std::vector<int>.

Что касается того, почему они написаны именно так, то это более широкий вопрос согласованности. Шаблоны во всей реализации Dinkumware стандартной библиотеки C++ (то, что поставляет Microsoft) используют _Ty в качестве базового имени для общих типов. Когда есть два типа, вы увидите _Ty1 и _Ty2. Когда для имени есть внутреннее определение типа, оно будет _Myty (для моего типа). Эта согласованность упрощает поддержку кода.

person Pete Becker    schedule 27.07.2020