Search for a trait of type is_allocator for use in enable_if

Is there a “sufficiently” reliable way to detect the dispenser in the template parameter. That is, I need something like a type trait is_allocatorthat can be used in enable_if:

Suppose that there is a future for a template template (with template parameter T):

    // Default ctor with allocator
    template <class Alloc, class... Args
        class Enable = typename std::enable_if<
            is_allocator<Alloc>::value
            and std::is_constructible<T, Args...>::value
        >::type
    >
    future(const Alloc& a, Args&&... args)
    : _shared_value(std::allocate_shared<T>(a, std::forward<T>(args...))
    {
    }



    // Default ctor (without allocator)
    template <class... Args
        class Enable = typename std::enable_if<
            std::is_constructible<T, Args...>::value
        >::type
    >
    future(Args&&... args)
    : _shared_value(std::make_shared<T>(std::forward<T>(args...))
    {
    }

Here _shared_valueis std::shared_pointer<T>.

+4
source share
2 answers

There is no such trait in the standard library is_allocator, but you can write it yourself:

#include <vector>
#include <utility>

template <class T>
class is_allocator
{
    typedef char yes;
    typedef long no;

    // you can extend this with many more checks on the allocator interface
    template <class C> static yes check( decltype(std::declval<C>().allocate(0)) );

    template <class C> static no  check(...);
public:
    enum { value = sizeof(check<T>(0)) == sizeof(yes) };
};

int main()
{
    std::vector<int> v { 1, 2 };
    using V = decltype(v)::value_type;
    using A = decltype(v)::allocator_type;
    static_assert(!is_allocator<V>::value, "");
    static_assert( is_allocator<A>::value, "");
}

Live example .

, - allocate(size_type), decltype(). , check<T>(0) enum, value true. static_assert std::vector.

, , has_allocate, has_deallocate -, Allocator . , is_allocator .

+5

, @TemplateRex @Casey, :

- is_allocator , ( Allocator) value_type, allocate(n) deallocate(ptr, n), ptr result_type allocate.

- , :

(): @Casey:

template <class T>
struct __has_allocate
{
private:
    template <class U> static std::false_type test(...);
    template <class U> static std::true_type test(decltype(std::declval<U>().allocate(0)));
public:
    enum { value = decltype(test<T>(0))::value };
};


template <class T>
struct __has_value_type
{
private:
    template <class U> static std::false_type test(...);
    template <class U> static std::true_type test(typename U::value_type*);
public:
    enum { value = decltype(test<T>(0))::value };
};


template <class T, bool HasAllocate = has_allocate<T>::value>
struct __has_deallocate
{
private:

    typedef decltype(std::declval<T>().allocate(0)) pointer;

    template <class Alloc, class Pointer>
    static auto
    test(Alloc&& a, Pointer&& p)
    -> decltype(a.deallocate(p,0), std::true_type());

    template <class Alloc, class Pointer>
    static auto
    test(const Alloc& a, Pointer&& p)
    -> std::false_type;

public:
    enum { value = decltype(test<T>(std::declval<T>(), std::declval<pointer>()))::value };
};


template <class T>
struct __has_deallocate<T, false>
{
    enum { value = false };
};




template <class T>
struct is_allocator
{
    enum { value =  __has_value_type<T>::value
                and __has_allocate<T>::value
                and __has_deallocate<T>::value
    };
};



// Test:

static_assert(is_allocator<int>::value == false, "");
static_assert(is_allocator<std::allocator<int>>::value == true, "");
+1

Source: https://habr.com/ru/post/1523887/


All Articles