Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ when are typedefs in standard library containers not what you would expect?

Tags:

c++

c++11

stl

For which standard library container types are the typedefs within the container not what you would naively think?

In code, under which conditions on the type T and the container container_type do the following static checks not all evaluate to true:

typedef double T;
typedef std::vector<T> container_type;

std::is_same<typename container_type::value_type, T>::value; 
std::is_same<typename container_type::reference, T&>::value; 
std::is_same<typename container_type::const_reference, T const&>::value; 
std::is_same<typename container_type::pointer, T*>::value;  
std::is_same<typename container_type::const_pointer, T const*>::value;  

I only know of std::vector<bool>::reference which is not bool& (and probably this is the same for the const version thereof).

Are there others?

like image 288
davidhigh Avatar asked Oct 23 '14 15:10

davidhigh


1 Answers

For any container containing objects of type T, the standard (C++11 23.2.1/4) requires that:

  • container_type::value_type is T
  • container_type::reference is an lvalue of T, i.e. a T&
  • container_type::const_reference is a const lvalue of T, i.e. a const T&

pointer and const_pointer are not part of any of the Container requirements, they are simply convenience typedefs in the standard containers, taken from the container's allocator.

So, to answer your question:

value_type, reference and const_reference must be as you expect, otherwise the container does not satisfy Container requirements. Notice that this means (as e.g. Herb Sutter points out), that std::vector<bool> is not a container in the standard sense.

pointer and const_pointer are typedefs to the allocator types, so when you have a container with allocator A, they will differ from T* and T const* whenever std::allocator_traits<A>::pointer and std::allocator_traits<A>::const_pointer differ from them.

And to directly address the question of which standard containers satisfy these Container requirements:

  • std::array<T> does, per 23.3.2.1/3 (with some exceptions which don't affect the typedefs in question)
  • std::deque<T> does, per 23.3.3.1/2
  • std::forward_list<T> does, per 23.3.4.1/2 (with some exceptions which don't affect the typedefs in question)
  • std::list<T> does, per 23.3.5.1/2
  • std::vector<T> does (for T other than bool), per 23.3.6.1/2 (with some exceptions which don't affect the typedefs in question)
  • std::set<T> does, per 23.4.6.1/2
  • std::multiset<T> does, per 23.4.7.1/2
  • std::unrdered_set<T> does, per 23.5.6.1/2
  • std::unordered_multiset<T> does, per 23.5.7.1/2
  • std::basic_string<T> contains the typedefs in question (to the correct types) as per 21.4./5, even though the standard does not explicitly require it to satisfy the Container requirements. Note that value_type depends on the character traits, so std::basic_string<T, MyTraits> can have value_type other than T.

std::[unorderd_][multi]map don't qualify because they take more than one mandatory template parameter and use them to synthesise value_type.

std::valarray<T> does not qualify because it only provides the value_type typedef and none of the others.

like image 178
Angew is no longer proud of SO Avatar answered Oct 25 '22 09:10

Angew is no longer proud of SO