是否有“足够”可靠的方法来检测模板参数中的分配器。也就是说,我需要类似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>
。
答案 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, "");
}
上面的代码通过在allocate(size_type)
表达式中调用该函数来检查类型是否具有成员函数decltype()
。如果存在此类函数,check<T>(0)
将在enum
表达式中选择该重载,value
将变为true
。作为支票,您可以static_assert
的模板参数std::vector
进行检查。
显然,您可以通过使用一系列细粒度特征has_allocate
,has_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>>{}, "!");
}