在`enable_if`中查找要使用的`is_allocator`类型特征

时间:2014-01-27 11:19:04

标签: templates c++11 template-meta-programming sfinae enable-if

是否有“足够”可靠的方法来检测模板参数中的分配器。也就是说,我需要类似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_valuestd::shared_pointer<T>

3 个答案:

答案 0 :(得分: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, "");
}

Live Example

上面的代码通过在allocate(size_type)表达式中调用该函数来检查类型是否具有成员函数decltype()。如果存在此类函数,check<T>(0)将在enum表达式中选择该重载,value将变为true。作为支票,您可以static_assert的模板参数std::vector进行检查。

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

答案 1 :(得分:1)

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

帮助程序类模板is_allocator检查给定的模板参数(可能的分配器)是否具有嵌入类型value_type,是否实现成员allocate(n)以及它是否实现{{1}其中deallocate(ptr, n)的结果类型为ptr的结果类型。

仍然没有检查一些要求,您可以在此处看到:Requirements

(编辑):@ Casey评论后应用进一步改进:

allocate

答案 2 :(得分: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>>{}, "!");
}