Reputation: 60107
I've noticed std::
containers tend to have public
, in-class type aliases (typedef
/using
).
E.g., see Member Types at http://en.cppreference.com/w/cpp/container/vector.
How are they useful? Aren't they just a relic of times when C++ didn't have things like auto
and decltype
?
When implementing a custom container, should it have such typedef
s? What do I lose if I fail to provide them?
Upvotes: 10
Views: 335
Reputation: 311068
typedef(s) allow to separate implementations from interfaces.
Take into acount that early the C++ does not define auto
as it is defined now and decltype
was absent in the Standard.
But even now when you have auto
and decltype
sometimes it is better to specify explicitly the type of an object. Otherwise the code can be difficult to read or it can lead to errors.
Consider a simple example with type specifier auto
unsigned int x = 0;
long y = 0;
auto p = new auto( x + y );
Can you say what is the type of the pointer p?
Is expression *p
of unsigned type or signed type?
The answer depends on used platform. The type of p can be either long *
or unsigned long *
.
A similar problem exists for standard containers. So the Standard introduces general type names like size_type
that guarantees that this type is unsigned type but its width can vary among platform.
Also this allows to write generic code.
In my profile there is a reference to my article where I show a problem that is related that standard class std::bitset
does not have generic type size_type
. In this case if you need to substitute for example class std::vector<bool>
to std::bitset
you need to change the code everywhere where there was used either size_type
or some explicit type like size_t
.
Upvotes: 1
Reputation: 120031
If you want a standard-library-compatible container, you do have to supply the typedefs.
If you look at the documentation, e.g. at cppreference, you will see passages like this:
std::vector meets the requirements of Container, AllocatorAwareContainer, SequenceContainer, ContiguousContainer (for T other than bool) (since C++17) and ReversibleContainer.
If you look up Container or SequenceContainer or any other thing listed there, you will find a list of requirements, and the typedefs (or rather types—they don't have to be typedefs, though they often are) are among them.
So if you are building a Container in the standard sense of the term, you need to provide the typedefs (and of course satisfy all other requirements too).
C++11 could in theory loosen the requirements, but it didn't. Perhaps because
std::vector<int>::iterator
is a heck of a lot more readable than
decltype(std::declval<std::vector<int>>().begin())
Or perhaps for some other reason.
Upvotes: 7
Reputation: 26506
They are extremly usefull when dealing with meta-programing, period.
let's catch a container by reference once if it's a container of POD, and another time when it's not:
template <class T>
typename std::enable_if_t<std::is_pod<typename T::value_type>::value>
doSomething(T& container){
//do something
}
template <class T>
typename std::enable_if_t<!std::is_pod<typename T::value_type>::value>
doSomething(T& container){
//do something
}
I'm doing a lot of C++ for Windows, and since Windows API provide C structs, I use many techniques like these to diffrentiate between real C++ objects and WinApi structs.
Upvotes: 4