Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve optional nested type like std::allocator_traits?

Tags:

c++

c++11

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?

like image 711
Sherwood Wang Avatar asked Dec 25 '22 01:12

Sherwood Wang


1 Answers

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.

like image 150
Jonathan Wakely Avatar answered Feb 24 '23 03:02

Jonathan Wakely