I have the following code that compiles (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);
}
Here are my questions:
If I use T
instead of TT
I get an error that one T
shadows the other. OK fair enough, but in my case, I want T
to be the same with TT
. How can I enforce that? I guess I could use std::enable_if
and std::is_same
somehow? But in that case the code will become too hairy. Is there any less hairy solution for this?
I barely see code with template template parameters. Am I doing something that is not considered a good practice?
I don't really like the syntax of this solution. Is there a better way to do the same but with cleaner/simpler code?
While the code with the template template parameters is big ugly, it is quite obvious to understand what this code does: It just allows the user to specify his/her own mechanism to allocate memory for NDArrayHost
objects. Although this qualifies for a whole different/separate question: if you think that I am approaching the problem completely wrong, feel free to point me to a better solution (as long as is not very complex like Thrust
.
On way is to declare the base template in terms of types T
and Alloc
and then only provide a legal partial specialisation.
#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);
}
We could if we liked, add a specialisation to provide a diagnostic if the T's don't match:
/* 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");
};
Testing...
int main()
{
NDArrayHost<int, NDArrayHostAllocatorNew<int>> h(10);
// fails with static assert
// NDArrayHost<int, NDArrayHostAllocatorNew<double>> h2(10);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.