Я бы хотел использовать что-то вроде 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, "!" );
}