Recently I picked up the habit of typedef
ing various types within template classes, as is done in the standard library. For example, a container class might look something along the lines of:
template<typename T>
class custom_container {
public:
typedef T value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef std::size_t size_type;
reference operator[](size_type);
// etc...
};
However, after a while of using this, I began to question if it's really such a good idea, despite supposedly increasing readability and expression of intent.
It seems counter-intuitive that one would alias, say, T
to another type, since isn't anyone using the class expecting the value_type
to be T
, and only ever T
anyway (it is a custom_container<T>
after all)? Similarly, would users of such a class not always expect pointer
to be T*
and reference
to be T&
?
We make use of typedef
s to allow for ease of changing some aliased type to another if required, yet in the majority of the cases I come across, said typedef
s are redundant, and almost confusing, as it would never make sense to have the alias synonymise any other type. custom_container
probably wouldn't be fulfilling its expectations if value_type
was changed to anything else than T
– the user expects it is some sort of container of T
s.
Therefore, is it still useful and/or good design to make heavy use of typedef
s in template classes as done in the standard library?
Best Answer
These typedefs are useful for two reasons:
for abbreviating the names of very complicated types such as iterator types.
for writing robust generic code that makes use of your templated type and isn't aware of
T
. Pre C++11 you cannot write some generic code without using these typedefs, or at least not without cumbersome helper templates.Both of these reasons are less necessary since C++11:
decltype()
can be used to find many types like the value type, andauto
can be used to avoid spelling out complicated type names.But both of these have limits.
decltype()
can sometimes produce unexpected types, especially around constness, references, or when implicit conversions are involved. E.g. given astd::vector<bool> xs
, thevalue_type
isbool
butdecltype(xs[0])
would be some reference wrapper object, unlessxs
is const in which case it is abool
again. Accounting for that correctly (possibly viastd::decay
?) is very difficult.Since
auto
will happily resolve to any type, it is not suitable when you do want to document and enforce a specific type. In some places like function parameters you cannot useauto
(though this is already allowed by some compilers as an implicit function template declaration).