Why does std :: queue allow the use of redundant type specification?

The first declaration of the std :: queue STL library class is as follows:

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

This means that we can declare a type queue object with different types of specifications as follows:

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

Why is this possible? Wouldn't it be a safer type to declare a queue as follows:

 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 */ /* --------------------------------------------------------------- */ 

Most std :: queue implementations. I saw the implementation of value_type and size_type in the same way as you can see in my code above. Thus, the template parameter 'T' is used only for the default parameter of the template parameter 'container' (std :: deque).

I mean, I donโ€™t think it is โ€œexcellentโ€ that the float specification in the example declaration above is ignored; regardless of whether it works or not.

+4
source share
3 answers

It would not be safer to declare a queue like this:

The safer type is yes, but not so convenient. A regular queue user does not care about the underlying container, which is actually just an implementation detail. They only need the type of item. It also provides compatibility with other container classes.

It would be even better if the queue class could be used by specifying the class template for the container as follows:

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

But unfortunately, there is no good, portable way to do this in C ++.

+2
source

If you only care about preventing "stupid" cases, a simple integrity check is sufficient:

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

Or similar objects in C ++ 03.

+1
source

Logically, one would expect something like:

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

The problem is that std::deque will not match the template argument, because actually it is:

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

An additional argument to the template does not allow it to work. And if an additional argument was added to the second queue parameter, then most custom containers cannot be used because they would not have a second argument. An electric current solution wraps around this problem (while resolving the client, the code to instantiate std::queue<float> , for example, without worrying about the basic type of container).

And in the end, why not? Your example std::queue<float, std::deque<std::string> > will probably not compile, but what's wrong with something like std::queue<bool, std::vector<char> > (avoiding the problematic std::vector<bool> )? As long as there is an implicit conversion in both directions, it is up to the client to do what he wants. (In practice, of course, this is almost never a problem, because it is rare for client code to specify a container.)

0
source

All Articles