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)そのオーバーロードを選択し、は になります。チェックとして、のテンプレート パラメータでこれを行うことができます。enumvaluetruestatic_assertstd::vector

has_allocate明らかに、細粒度の特性の束has_deallocateと、標準の Allocator 要件全体を構成する他のすべての重要なメンバー関数を使用することで、このアプローチを改善できます。それができたら、is_allocatorこれらすべてのきめの細かい特性を論理的に定義することができます。

于 2014-01-27T12:13:46.350 に答える
1

@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, "");
于 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 に答える