Search code examples
c++templatesstlc++-concepts

How can I write a template/concept to check if a type meets the named requirement DefaultInsertable


While implementing my own forward_list class template, I saw that some of the methods such as resize() require the type be DefaultInsertable. According to the documentation, DefaultInsertable

Specifies that an instance of the type can be default-constructed in-place by a given allocator.

I understand what DefaultConstructable means and I can enforce that my type T meets this requirement either by using the default_initializable concept or with the following template:

template <typename = std::enable_if_t<(T(),T{},true),int*>>

where T is any type

But how could I verify that a type can be default-constructed in place by a given allocator?


Solution

  • The custom is_default_insertable type trait, which is true if the type T models DefaultInsertable for an allocator type A.

    To implement the condition, it is sufficient to verify whether the expression std::allocator_traits<A>::construct(std::declval<A&>(), std::declval<T*>()) is well-formed. The allocator type is not rebound because the construct() member function does not depend on it.

    namespace detail {
      template <typename, typename, typename = void>
      struct is_default_insertable
       : std::false_type {};
      
      template <typename T, typename A>
      struct is_default_insertable<T, A, std::void_t<decltype(std::allocator_traits<A>::construct(std::declval<A&>(), std::declval<T*>()))>>
       : std::true_type {};
    }
    
    template <typename T, typename A>
    struct is_default_insertable
     : detail::is_default_insertable<T, A> {};
    
    template <typename T, typename A>
    inline constexpr bool is_default_insertable_v = is_default_insertable<T, A>::value;
    

    Alternatively, the default_insertable concept, which is equivalent to the above type trait, can be implemented in the following way.

    template <typename T, typename A>
    concept default_insertable = requires(A& x, T* y)
    {
      std::allocator_traits<A>::construct(x, y);
    };