Как сгруппировать разные статические классы? - PullRequest
1 голос
/ 21 апреля 2019

У меня есть шаблонный статический класс с различными специализациями, например:

template<typename Parameter >
class MyClass
{};

 template<>
class MyClass<Parameter1>
{
public:
     static constexpr Integer myarray[]={0};
     static constexpr Integer myarraysize=1;    
 };

  template<>
class MyClass<Parameter2>
{
public:
     static constexpr Integer myarray[]={0,1};
     static constexpr Integer myarraysize=2;    
 };

Теперь я хотел бы как-то сгруппировать эту информацию в новый класс

template<typename MyClass1, typename MyClasses... >
class MyGroupClass{
//do something...}

, где я мог быдать в качестве параметров шаблона variadic различные классы, и тогда я смогу получить доступ к различным статическим методам.

Например, я хотел бы получить что-то как MyGroupClass[n]::myarraysize для доступа к myarraysize, относящемуся к n-му MyClass.

Я представляю, что мог бы создать кортеж (таким образом, имея std::get<n>()), но мне не очень понятно, как это сделать, поскольку у меня нет конструкторов для таких отдельных статических классов.Ведь классы статичны.

Можно ли добиться того, чего я хочу?Если да, не могли бы вы, пожалуйста, просветить меня?Спасибо.

1 Ответ

0 голосов
/ 21 апреля 2019

Я бы хотел использовать что-то вроде MyGroupClass [n] :: myarraysize для доступа к myarraysize, связанному с n-м MyClass. Я полагаю, я мог бы создать кортеж (так что с std :: get ()),

Мне кажется, что нужно различать два случая.

(1) когда myarraysize в разных классах имеют разных типов, вы можете создать std::tuple разных размеров и использовать std::get() для извлечения значений.

К примеру

template <typename ... Ts>
struct MyGroupStruct
 {
   const std::tuple<decltype(Ts::myarraysize)...> tpl { Ts::myarraysize... };

   template <std::size_t N>
   auto get () const -> decltype(std::get<N>(tpl))
    { return std::get<N>(tpl); }
 };

Начиная с C ++ 14, вы можете избежать конечного типа возврата для get() и написать просто

   template <std::size_t N>
   auto get () const
    { return std::get<N>(tpl); }

Обратите внимание, что MyGroupStruct::get() получает индекс (N) в качестве параметра шаблона. Так что это требует известного значения времени компиляции. Это необходимо, потому что тип, возвращаемый из метода шаблона, отличается в зависимости от индекса, поэтому должно быть известным временем компиляции.

(2) когда все myarraysize в разных классах имеют одинаковый тип, вы также можете создать std::array этого типа; что-то вроде

template <typename ... Ts>
struct MyGroupStruct
 {
   using myType = typename std::tuple_element<0u, 
      std::tuple<decltype(Ts::myarraysize)...>>::type;

   const std::array<myType, sizeof...(Ts)> arr {{ Ts::myarraysize... }};

   myType & get (std::size_t n)
    { return arr[n]; }
 };

Обратите внимание, что в этом случае возвращаемое значение для get() всегда одинаково, поэтому он может получить индекс времени выполнения в качестве (не шаблона) параметра.

Ниже приведен полный пример компиляции для случая разных типов (на основе кортежа)

#include <tuple>
#include <string>
#include <iostream>

struct Par1 {};
struct Par2 {};
struct Par3 {};
struct Par4 {};

template <typename>
struct MyStruct;

template <>
struct MyStruct<Par1>
 { static constexpr int myarraysize {1}; };

constexpr int MyStruct<Par1>::myarraysize;

template <>
struct MyStruct<Par2>
 { static constexpr long myarraysize {2l}; };

constexpr long MyStruct<Par2>::myarraysize;

template <>
struct MyStruct<Par3>
 { static constexpr long long myarraysize {3ll}; };

constexpr long long MyStruct<Par3>::myarraysize;

template <>
struct MyStruct<Par4>
 { static const std::string myarraysize; };

const std::string MyStruct<Par4>::myarraysize {"four"};

template <typename ... Ts>
struct MyGroupStruct
 {
   const std::tuple<decltype(Ts::myarraysize)...> tpl { Ts::myarraysize... };

   template <std::size_t N>
   auto get () const -> decltype(std::get<N>(tpl))
    { return std::get<N>(tpl); }
 };

int main ()
 {
   MyGroupStruct<MyStruct<Par1>, MyStruct<Par2>,
                 MyStruct<Par3>, MyStruct<Par4>> mgs;

   std::cout << mgs.get<0>() << std::endl;
   std::cout << mgs.get<1>() << std::endl;
   std::cout << mgs.get<2>() << std::endl;
   std::cout << mgs.get<3>() << std::endl;

   static_assert( std::is_same<int const &,
                               decltype(mgs.get<0>())>::value, "!" );
   static_assert( std::is_same<long const &,
                               decltype(mgs.get<1>())>::value, "!" );
   static_assert( std::is_same<long long const &,
                               decltype(mgs.get<2>())>::value, "!" );
   static_assert( std::is_same<std::string const &,
                               decltype(mgs.get<3>())>::value, "!" );
 }

А теперь полный пример компиляции для случая с равными типами (на основе массива)

#include <tuple>
#include <array>
#include <string>
#include <iostream>

struct Par1 {};
struct Par2 {};
struct Par3 {};
struct Par4 {};

template <typename>
struct MyStruct;

template <>
struct MyStruct<Par1>
 { static constexpr int myarraysize {1}; };

constexpr int MyStruct<Par1>::myarraysize;

template <>
struct MyStruct<Par2>
 { static constexpr int myarraysize {2}; };

constexpr int MyStruct<Par2>::myarraysize;

template <>
struct MyStruct<Par3>
 { static constexpr int myarraysize {3}; };

constexpr int MyStruct<Par3>::myarraysize;

template <>
struct MyStruct<Par4>
 { static const int myarraysize {4}; };

const int MyStruct<Par4>::myarraysize;

template <typename ... Ts>
struct MyGroupStruct
 {
   using myType = typename std::tuple_element<0u, 
         std::tuple<decltype(Ts::myarraysize)...>>::type;

   const std::array<myType, sizeof...(Ts)> arr {{ Ts::myarraysize... }};

   myType & get (std::size_t n)
    { return arr[n]; }
 };

int main ()
 {
   MyGroupStruct<MyStruct<Par1>, MyStruct<Par2>,
                 MyStruct<Par3>, MyStruct<Par4>> mgs;

   std::cout << mgs.get(0) << std::endl;
   std::cout << mgs.get(1) << std::endl;
   std::cout << mgs.get(2) << std::endl;
   std::cout << mgs.get(3) << std::endl;

   static_assert( std::is_same<int const &,
                               decltype(mgs.get(0))>::value, "!" );
 }

- РЕДАКТИРОВАТЬ -

ОП просит

как изменить код, если я хочу получить доступ к myarray, а не только к myarraysize?

С массивом в стиле C немного сложнее, потому что вы не можете инициализировать кортеж массивов в стиле C с массивами в стиле C.

Я предлагаю вам использовать кортеж из ссылок на массивы в стиле C.

Итак, с учетом некоторых MyClass только с myarray (зачем добавлять размер, если вы можете вывести его?)

template <typename>
struct MyStruct;

template <>
struct MyStruct<Par1>
 { static constexpr int myarray[] {0}; };

constexpr int MyStruct<Par1>::myarray[];

// other MyStruct specializations ...

Вы можете добавить кортеж ссылок (кортеж, а не std::array, потому что int[1], int[2], int[3] и int[4] - все разные типы) и std::array<std::size_t, sizeof...(Ts)> для размеров.

Я имею в виду ... вы можете написать что-то следующим образом

template <typename ... Ts>
struct MyGroupStruct
 {
   std::tuple<decltype(Ts::myarray) & ...> const tpl { Ts::myarray... };

   std::array<std::size_t, sizeof...(Ts)> const arr
    {{ sizeof(Ts::myarray)/sizeof(Ts::myarray[0])... }};

   template <std::size_t N>
   auto getArr () const -> decltype(std::get<N>(tpl))
    { return std::get<N>(tpl); }

   std::size_t getSize (std::size_t n) const
    { return arr[n]; }
 };

что это означает "const -> decltype (std :: get (tpl))"? *

const не имеет отношения к decltype().

const, после списка параметров метода, сказать, что метод может использоваться также постоянным объектом, потому что не изменяет переменные-члены.

Относительно decltype() ищите «конечный тип возврата» для получения дополнительной информации.

Короче говоря, для C ++ 11 идея заключается в том, что в

auto foo () -> decltype(something)
 { return something; }

auto скажите "присмотри -> тип возврата", а decltype(something) - это "тип something"

Вы также можете написать

decltype(something) foo ()
 { return something; }

, если something известен перед списком аргументов функции, но форма auto / -> decltype(something) становится полезной, когда something содержит параметры шаблона

К примеру

template <typename T1, typename T2>
auto sum (T1 const & t1, T2 const & t2) -> decltype(t1+t2)
 { return t1+t2; }

Начиная с C ++ 14 «конечный тип возврата» используется реже, потому что вы можете просто написать

template <typename T1, typename T2>
auto sum (T1 const & t1, T2 const & t2)
 { return t1+t2; }

потому что auto говорят компилятору "выводить тип возвращаемого значения из выражения return" (в данном случае из t1+t2.

Это позволяет избежать большого количества избыточностей.

И можем ли мы использовать "auto" также в C ++ 11?

auto как тип возвращаемого значения? Без завершающего типа возврата?

К сожалению, доступно только начиная с C ++ 14.

Следует еще один полный пример с myarray и выведенными размерами.

#include <tuple>
#include <array>
#include <string>
#include <iostream>

struct Par1 {};
struct Par2 {};
struct Par3 {};
struct Par4 {};

template <typename>
struct MyStruct;

template <>
struct MyStruct<Par1>
 { static constexpr int myarray[] {0}; };

constexpr int MyStruct<Par1>::myarray[];

template <>
struct MyStruct<Par2>
 { static constexpr int myarray[] {0, 1}; };

constexpr int MyStruct<Par2>::myarray[];

template <>
struct MyStruct<Par3>
 { static constexpr int myarray[] {0, 1, 2}; };

constexpr int MyStruct<Par3>::myarray[];

template <>
struct MyStruct<Par4>
 { static constexpr int myarray[] {0, 1, 2, 3}; };

constexpr int MyStruct<Par4>::myarray[];

template <typename ... Ts>
struct MyGroupStruct
 {
   std::tuple<decltype(Ts::myarray) & ...> const tpl { Ts::myarray... };

   std::array<std::size_t, sizeof...(Ts)> const arr
    {{ sizeof(Ts::myarray)/sizeof(Ts::myarray[0])... }};

   template <std::size_t N>
   auto getArr () const -> decltype(std::get<N>(tpl))
    { return std::get<N>(tpl); }

   std::size_t getSize (std::size_t n) const
    { return arr[n]; }
 };

int main ()
 {
   MyGroupStruct<MyStruct<Par1>, MyStruct<Par2>,
                 MyStruct<Par3>, MyStruct<Par4>> mgs;

   std::cout << mgs.getSize(0) << std::endl;
   std::cout << mgs.getSize(1) << std::endl;
   std::cout << mgs.getSize(2) << std::endl;
   std::cout << mgs.getSize(3) << std::endl;

   static_assert( std::is_same<std::size_t,
                               decltype(mgs.getSize(0))>::value, "!" );

   std::cout << mgs.getArr<0>()[0] << std::endl;
   std::cout << mgs.getArr<1>()[1] << std::endl;
   std::cout << mgs.getArr<2>()[2] << std::endl;
   std::cout << mgs.getArr<3>()[3] << std::endl;

   static_assert( std::is_same<int const (&)[1],
                               decltype(mgs.getArr<0>())>::value, "!" );
   static_assert( std::is_same<int const (&)[2],
                               decltype(mgs.getArr<1>())>::value, "!" );
   static_assert( std::is_same<int const (&)[3],
                               decltype(mgs.getArr<2>())>::value, "!" );
   static_assert( std::is_same<int const (&)[4],
                               decltype(mgs.getArr<3>())>::value, "!" );    
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...