Как применить ограничения между шаблоном и параметрами шаблона в 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
каким-то образом? Но в этом случае код станет слишком волосатым. Есть ли менее волосатое решение для этого?Я едва вижу код с параметрами шаблона шаблона. Я делаю что-то, что не считается хорошей практикой?
Мне не очень нравится синтаксис этого решения. Есть ли лучший способ сделать то же самое, но с более чистым / простым кодом?
Хотя код с параметрами шаблона шаблона очень уродлив, совершенно очевидно, что этот код понимает: он просто позволяет пользователю указать собственный механизм выделения памяти для
NDArrayHost
объекты. Хотя это подходит для совершенно другого / отдельного вопроса: если вы считаете, что я подхожу к проблеме совершенно неправильно, не стесняйтесь указывать мне на лучшее решение (пока оно не очень сложное, какThrust
,
1 ответ
По пути стоит объявить базовый шаблон с точки зрения типов 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);
}