如何对不同的静态类进行分组?

时间:2019-04-21 12:27:55

标签: c++ c++11 static variadic-templates stdtuple

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

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

在这里我可以给不同的类作为变量模板参数,然后可以访问不同的静态方法。

例如,我想访问MyGroupClass[n]::myarraysize之类的东西来访问与第n个myarraysize相关的MyClass

我想我可以创建一个元组(因此拥有std::get<n>()),但是我对如何做到这一点并不十分清楚,因为我没有此类静态类的构造函数。毕竟,这些类是静态的。

能否实现我想要的?如果是这样,请您启发我吗?谢谢。

1 个答案:

答案 0 :(得分:0)

  

我想使用MyGroupClass [n] :: myarraysize来访问与第n个MyClass相关的myarraysize。我想我可以创建一个元组(因此拥有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, "!" );
 }

-编辑-

OP询问

  

如果我还要访问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))”是什么意思?

constdecltype()无关。

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得出。

这避免了很多重复。

  

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