如何在 C++17 中强制模板和模板模板参数之间的约束
How to enforce constraints between template and template template parameters in C++17
我有以下编译代码(GCC7、C++17):
template<typename T>
struct NDArrayHostAllocatorNew
{
static T* allocate(std::size_t size) {
return new T[size];
}
static void deallocate(const T* ptr){
delete [] ptr;
}
};
template<typename T, template<typename TT> typename Alloc>
class NDArrayHost
{
public:
typedef Alloc<T> allocator_type;
NDArrayHost(std::size_t size);
private:
T* m_data;
};
template<typename T, template<typename TT> typename Alloc>
NDArrayHost<T, Alloc>::NDArrayHost(std::size_t size)
{
m_data = allocator_type::allocate(size);
}
这是我的问题:
如果我使用 T
而不是 TT
,我会得到一个 T
遮盖另一个的错误。好吧,但就我而言,我希望 T
与 TT
相同。我该如何执行?我想我可以以某种方式使用 std::enable_if
和 std::is_same
吗?但在那种情况下,代码会变得太毛茸茸了。有没有更简单的解决方案?
我几乎看不到带有模板模板参数的代码。我是否在做一些不被认为是好的做法?
我不太喜欢这个解决方案的语法。有没有更好的方法来做同样的事情,但使用 cleaner/simpler 代码?
虽然带有模板模板参数的代码很丑陋,但很容易理解这段代码的作用:它只是允许用户指定 his/her 自己的内存分配机制对于 NDArrayHost
个对象。尽管这符合整个 different/separate 问题的条件:如果您认为我完全错误地解决了这个问题,请随时为我指出更好的解决方案(只要不是像 Thrust
那样非常复杂)。
一种方法是根据类型 T
和 Alloc
声明基本模板,然后只提供合法的偏特化。
#include <cstddef>
#include <memory>
template<typename T>
struct NDArrayHostAllocatorNew
{
static T* allocate(std::size_t size) {
return new T[size];
}
static void deallocate(const T* ptr){
delete [] ptr;
}
};
/*
* declare the base template in terms of T and allocator
*/
template<typename T, typename Alloc>
class NDArrayHost;
/*
* only provide legal specialisations
*/
template<class T, template<class> class Alloc>
class NDArrayHost<T, Alloc<T>>
{
public:
typedef Alloc<T> allocator_type;
NDArrayHost(std::size_t size);
private:
T* m_data;
};
template<class T, template<class> class Alloc>
NDArrayHost<T, Alloc<T>>::NDArrayHost(std::size_t size)
{
m_data = allocator_type::allocate(size);
}
如果我们愿意,我们可以添加一个专门化以在 T 不匹配时提供诊断:
/* specifically disallow illegal specialisations */
template<class T, class U, template<class> class Alloc>
class NDArrayHost<T, Alloc<U>>
{
static_assert(std::is_same<T, U>(), "meh");
};
正在测试...
int main()
{
NDArrayHost<int, NDArrayHostAllocatorNew<int>> h(10);
// fails with static assert
// NDArrayHost<int, NDArrayHostAllocatorNew<double>> h2(10);
}
我有以下编译代码(GCC7、C++17):
template<typename T>
struct NDArrayHostAllocatorNew
{
static T* allocate(std::size_t size) {
return new T[size];
}
static void deallocate(const T* ptr){
delete [] ptr;
}
};
template<typename T, template<typename TT> typename Alloc>
class NDArrayHost
{
public:
typedef Alloc<T> allocator_type;
NDArrayHost(std::size_t size);
private:
T* m_data;
};
template<typename T, template<typename TT> typename Alloc>
NDArrayHost<T, Alloc>::NDArrayHost(std::size_t size)
{
m_data = allocator_type::allocate(size);
}
这是我的问题:
如果我使用
T
而不是TT
,我会得到一个T
遮盖另一个的错误。好吧,但就我而言,我希望T
与TT
相同。我该如何执行?我想我可以以某种方式使用std::enable_if
和std::is_same
吗?但在那种情况下,代码会变得太毛茸茸了。有没有更简单的解决方案?我几乎看不到带有模板模板参数的代码。我是否在做一些不被认为是好的做法?
我不太喜欢这个解决方案的语法。有没有更好的方法来做同样的事情,但使用 cleaner/simpler 代码?
虽然带有模板模板参数的代码很丑陋,但很容易理解这段代码的作用:它只是允许用户指定 his/her 自己的内存分配机制对于
NDArrayHost
个对象。尽管这符合整个 different/separate 问题的条件:如果您认为我完全错误地解决了这个问题,请随时为我指出更好的解决方案(只要不是像Thrust
那样非常复杂)。
一种方法是根据类型 T
和 Alloc
声明基本模板,然后只提供合法的偏特化。
#include <cstddef>
#include <memory>
template<typename T>
struct NDArrayHostAllocatorNew
{
static T* allocate(std::size_t size) {
return new T[size];
}
static void deallocate(const T* ptr){
delete [] ptr;
}
};
/*
* declare the base template in terms of T and allocator
*/
template<typename T, typename Alloc>
class NDArrayHost;
/*
* only provide legal specialisations
*/
template<class T, template<class> class Alloc>
class NDArrayHost<T, Alloc<T>>
{
public:
typedef Alloc<T> allocator_type;
NDArrayHost(std::size_t size);
private:
T* m_data;
};
template<class T, template<class> class Alloc>
NDArrayHost<T, Alloc<T>>::NDArrayHost(std::size_t size)
{
m_data = allocator_type::allocate(size);
}
如果我们愿意,我们可以添加一个专门化以在 T 不匹配时提供诊断:
/* specifically disallow illegal specialisations */
template<class T, class U, template<class> class Alloc>
class NDArrayHost<T, Alloc<U>>
{
static_assert(std::is_same<T, U>(), "meh");
};
正在测试...
int main()
{
NDArrayHost<int, NDArrayHostAllocatorNew<int>> h(10);
// fails with static assert
// NDArrayHost<int, NDArrayHostAllocatorNew<double>> h2(10);
}