5

是否有一种“足够”可靠的方法来检测模板参数中的分配器。也就是说,我需要类似is_allocator类型特征的东西,它可以用于enable_if

假设有一个类模板future(带有模板参数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...))
    {
    }

这里,_shared_value是一个std::shared_pointer<T>

4

3 回答 3

5

标准库中没有这样is_allocator的特性,但您可以自己编写一个:

#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, "");
}

活生生的例子

上面的代码通过在表达式中allocate(size_type)调用该函数来检查类型是否具有成员函数。decltype()如果存在这样的函数,则将在表达式check<T>(0)中选择该重载,并且将变为。作为检查,您可以对 a 的模板参数执行此操作。enumvaluetruestatic_assertstd::vector

显然,您可以通过拥有一堆细粒度的特征以及构成标准中整个分配器要求的所有其他基本成员函数来改进这种has_allocate方法has_deallocate。完成此操作后,您可以将is_allocator所有这些细粒度特征定义为逻辑特征。

于 2014-01-27T12:13:46.350 回答
1

好吧,在从@TemplateRex 和@Casey 得到非常有用的答案和评论后,我终于想出了以下改进的解决方案:

辅助类模板is_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, "");
于 2014-01-27T16:27:00.620 回答
0

这里有一个 Boost 提案:https ://tickcpp.readthedocs.io/en/latest/tick/traits/is_allocator.html

我个人的解释可以翻译成这个检测成语。(虽然,像往常一样使用概念,我不知道这是否会限制/过度限制概念。)

#include<utility> // declval

template<
    class A, 
    class P = typename A::pointer, class S = typename A::size_type,
    typename = decltype( 
        std::declval<A const&>()==A{std::declval<A const&>()},
        std::declval<A&>().deallocate(P{std::declval<A&>().allocate(std::declval<S>())}, std::declval<S>())
    )
>
std::true_type  is_allocator_aux(A const&);
std::false_type is_allocator_aux(...);

template<class A> struct is_allocator : decltype(is_allocator_aux(std::declval<A const&>())){};

可以这样使用:

#include<memory>
#include<vector>
int main(){
    static_assert(is_allocator<std::allocator<double>>{});
    static_assert(not is_allocator<double>{}, "!");
    static_assert(not is_allocator<std::vector<double>>{}, "!");
}
于 2019-10-31T04:36:01.207 回答