如何分组不同的静态类?

How to group different static classes?

我有一个具有不同专业化的静态模板 class,如下所示:

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

现在我想以某种方式将这些信息分组到一个新的 class

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

我可以在其中提供不同的 classes 作为可变模板参数,然后我可以访问不同的静态方法。

例如,我想用 MyGroupClass[n]::myarraysize 来访问与第 n 个 MyClass.

相关的 myarraysize

我想我可以创建一个元组(所以有 std::get<n>()),但我不太清楚如何做到这一点,因为我没有这种单一静态 classes 的构造函数.毕竟,classes 是静态的。

是否可以达到我想要的效果?如果是这样,你能赐教吗?谢谢。

I would like to to something as MyGroupClass[n]:: myarraysize to access myarraysize related to n-th MyClass. I imagine I could create a tuple (so having 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() 的尾随 return 类型并简单地编写

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

观察到 MyGroupStruct::get() 接收索引 (N) 作为模板参数。所以它需要一个编译时已知值。这是必要的,因为从模板方法中编辑的类型 return 与索引不同,因此 必须 是已知的编译时间。

(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() 的 return 值始终相同,因此它可以接收 运行 时间索引作为(非模板)参数。

以下是不同类型(基于元组)案例的完整编译示例

#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, "!" );
 }

-- 编辑--

OP 询问

how to change the code if I want to access also myarray and not only myarraysize?

C 风格的数组稍微复杂一些,因为你不能用 C 风格的数组初始化 C 风格数组的元组。

我建议您对 C 样式数组使用 引用 的元组。

所以,给定一些只有 myarrayMyClass(为什么要在可以推断的情况下添加大小?)

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

what does this stand for "const -> decltype(std::get(tpl))"?

constdecltype().

无关

const,在方法参数列表后,说该方法也可以被常量对象使用,因为不改变成员变量。

关于 decltype() 查找 "trailing return type" 了解更多信息。

简而言之,对于 C++11,想法是在

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

auto 说 "look after -> for the return type" 而 decltype(something) 是 "the type of 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 开始,"trailing return type" 较少使用,因为您可以简单地编写

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

因为 auto 对编译器说 "deduce the return type from the return expression"(所以在这种情况下来自 t1+t2

这避免了很多冗余。

And can we use "auto" also in C++11?

auto 为 return 类型?没有尾随 return 类型?

遗憾的是,仅从 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, "!" );    
 }