#c #templates #nested
#c #шаблоны #вложенный
Вопрос:
У меня такая ситуация:
template<unsigned int N>
class Base
{
public:
Base(){}
int myint[N];
};
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
BaseWrapper(){}
};
template<typename T>
class User
{
public:
User(){}
//int myint[T::N]; //How to statically allocate using M or N from above?
};
int main(void)
{
User<BaseWrapper<10> > myuser;
// Do something with User::myint here.
}
Я хочу иметь возможность использовать параметр non-type аргумента шаблона, чтобы User
статически распределять данные в User
классе. Я знаю, что могу использовать параметры шаблона шаблона для создания BaseWrapper<M>
внутри User
, но это не мой предпочтительный подход. Есть какие-нибудь простые методы для этого?
Спасибо!
Ответ №1:
Добавьте static const unsigned int Size = N;
в свой класс.
Пример:
template<unsigned int N>
class Base
{
public:
Base(){}
int myint[N];
static const unsigned int Size = N;
};
Тогда N
доступно как T::Size
в вашем User
классе.
Ответ №2:
Решение 1
Объявляйте постоянные статические данные-члены как:
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
static const unsigned int size = M; //add this line!
BaseWrapper(){}
};
Затем используйте это как T::size
в User
классе:
template<typename T>
class User
{
public:
User(){}
int myint[T::size]; //you can do this!
};
Решение 2
Или, если вы не можете добавить size
в качестве участника (по какой-либо причине), вы можете использовать этот подход как:
template<typename T> struct get;
template<unsigned int N>
struct get< BaseWrapper<N> > //partial specialization!
{
static const unsigned int size = N;
};
template<typename T>
class User
{
public:
User(){}
int myint[get<T>::size]; //get the size!
};
Ответ №3:
Вы можете предоставить параметр шаблона как статическую переменную-член класса:
template<unsigned int M>
class BaseWrapper : Base<M>
{
public:
static const int counter = M;
BaseWrapper(){}
};
Затем вы можете использовать этот статический элемент в своем User
классе:
template<typename T>
class User
{
public:
User(){}
int myint[T::counter];
};
Ответ №4:
Самый простой способ, который уже упоминался другими, заключается в добавлении статического элемента к Basewrapper
, который инициализируется N
.
Однако, если по какой-то причине вы не можете изменить User
, есть также способ получить доступ к N:
template<typename T> struct get_N;
template<unsigned int N> struct get_N<Basewrapper<N> > { unsigned int const value = N; };
Теперь в вашем User
шаблоне вы можете просто писать get_N<T>::value
.
Одним из преимуществ этого является то, что вы можете адаптировать любой тип постфактум, не касаясь его определения, поэтому, если вы когда-нибудь захотите создать экземпляр User
для чего-либо другого, кроме Basewrapper
, скажем, для Newbasewrapper
, вы просто добавляете строку
template<unsigned int N> struct get_N<Newbasewrapper<N> > { unsigned int const value = N; };
или, если Newbasewrapper принимает некоторый тип в качестве аргумента шаблона и предоставляет значение N в качестве статического постоянного элемента,
template<typename T> struct get_N<Basewrapper<T> > { unsigned int const value = Basewrapper<T>::N; };