Почему std :: queue допускает избыточную спецификацию типов? - PullRequest
4 голосов
/ 18 апреля 2011

Предварительное объявление класса библиотеки STL std :: queue выглядит следующим образом:

namespace std {
    template<typename T, class container = deque<T>> class queue
}

Это означает, что мы можем объявить объект очереди типа с различными спецификациями типа, такими как:

std::queue<float, std::deque<std::string>> string_queue;

Почему это возможно?Не было бы намного безопаснее объявить очередь следующим образом:

template<class implementation>
class queue_base
{
private:
    implementation m_impl;
    /* ----------------------------------------------------------- */

public:
    typedef implementation                      container_type;
    typedef typename implementation::size_type  size_type;
    typedef queue_base<implementation>          this_type;
    typedef typename implementation::value_type value_type;
    /* ----------------------------------------------------------- */

    queue_base         ();
    queue_base         (queue_base const& other);
    explicit queue_base(container_type const& other);
    /* ----------------------------------------------------------- */

    value_type&       back ();
    value_type const& back () const;
    bool              empty() const;
    value_type&       front();
    value_type const& front() const;
    void              pop  ();
    void              push (value_type const& value);
    size_type         size () const;
    /* ----------------------------------------------------------- */
}; /* template<class> class queue_base */
/* --------------------------------------------------------------- */

Большинство реализаций std :: queue, которые я видел, реализуют 'value_type' и 'size_type' таким же образом, как вы можете видетьв моем коде выше.Таким образом, параметр шаблона 'T' используется только для параметра по умолчанию для параметра шаблона 'container' (std :: deque).

Я имею в виду, я не думаю, что это "хорошо", что спецификация floatв приведенном выше примере объявления игнорируется;независимо от того, работает это или нет.

Ответы [ 3 ]

2 голосов
/ 18 апреля 2011

Не было бы безопаснее объявить очередь следующим образом:

Более безопасно типа, но не так удобно.Обычный пользователь queue не заботится о нижележащем контейнере, который на самом деле просто деталь реализации.Они заботятся только о типе элемента.Это также для согласованности с другими классами контейнеров.

Еще лучше было бы, если бы класс queue можно было использовать, указав шаблон класса для контейнера следующим образом:

std::queue<int, std::list> myqueue;

Но, к сожалению, нет хорошего, портативного способа сделать это в C ++.

1 голос
/ 18 апреля 2011

Если вы заботитесь только о предотвращении «глупых» случаев, достаточно простой проверки целостности:

template <typename T, typename Container>
class queue
{
  static_assert(std::is_same<T, typename Container::value_type>::value,
    "queue require T and Container::value_type to be identical");
};

или аналогичные средства в C ++ 03.

0 голосов
/ 18 апреля 2011

Логически, можно ожидать что-то вроде:

template<typename T, template<typenameU> class C = std::deque>
class queue
{
protected:
    C<T> c;
public:
    //  ...
};

Проблема в том, что std::deque не будет соответствовать аргументу шаблона, потому что на самом деле:

template<typename T, typename Allocator = allocator<T> >
class deque ...

Дополнительный аргумент шаблона не позволяет ему работать.И если дополнительный аргумент был добавлен ко второму параметру queue, то большинство пользовательских контейнеров не может быть использовано, потому что у них не будет второго аргумента.Текущее решение обходит эту проблему (хотя все еще позволяет клиентскому коду создавать экземпляр std::queue<float>, например, не беспокоясь о базовом типе контейнера).

И в конце концов, почему бы и нет?Ваш пример std::queue<float, std::deque<std::string> >, вероятно, не скомпилируется, но что не так с чем-то вроде std::queue<bool, std::vector<char> > (избегая проблемных std::vector<bool>)?Пока есть неявное преобразование в обоих направлениях, клиент должен убедиться, что он делает то, что хочет.(На практике, конечно, это почти никогда не проблема, потому что в коде клиента редко указывается контейнер.)

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