An allocator can optionally have nested types like pointer
, const_pointer
. But one can always use these interface with std::allocator_traits<Allocator>
, which would provide a default version of these types if they are absent in Allocator
.
How is std::allocator_traits
implemented? How can a template choose a default version of nested type when it's absent?
The solution is to refer to the type T::pointer
in a context where it does not cause an error if it is not a valid type, instead it causes template argument deduction to fail. The general form of this is known as SFINAE, which stands for "Substitution Failure Is Not An Error". For a explanation of how it works see my SFINAE Functionality Is Not Arcane Esoterica presentation.
There are various techniques, often involving overloaded function templates, but my current favourite uses the void_t
idiom to select a partial specialization of a class template:
template<typename T>
using void_t = void;
template<typename T, typename = void>
struct get_pointer
{
using type = typename T::value_type*;
};
template<typename T>
struct get_pointer<T, void_t<typename T::pointer>>
{
using type = typename T::pointer;
};
Now given an allocator type A
you can use typename get_pointer<A>::type
to refer to A::pointer
if that exists, otherwise A::value_type*
The code above works because when A::pointer
is a valid type the partial specialization matches and is more specialized than the primary template, and so gets used. When A::pointer
is not a valid type the partial specialization is ill-formed, so the primary template is used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With