Доступ к вложенным параметрам шаблона без аргументов шаблона шаблона

#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; };