Looking for an `is_allocator` Type Trait for Use in `enable_if`
c++11, enable-if, sfinae, template-meta-programming, templates
Solution
There is no such `is_allocator` trait in the Standard Library, but you can write one 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.
The above code checks whether a type has a member function `allocate(size_type)` by calling that function inside a `decltype()` expression. If such a function exists, the `check<T>(0)` will select that overload in the `enum` expression and the `value` will become `true`. As a check, you can `static_assert` this on the template parameters of a `std::vector`.
Obviously, you could improve this approach by having a bunch of fine-grained traits `has_allocate`, `has_deallocate` and all the other essential member function that make up the entire Allocator requirements in the Standard. Once you have done that, you can define `is_allocator` as the logical and over all these fine-grained traits.
Problem
Is there a "sufficiently" reliable way to detect an allocator in a template parameter. That is, I need something like a `is_allocator` type trait which can be used in an `enable_if`: Suppose there is a class template future (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_value` is a `std::shared_pointer<T>`.