Могу ли я создать шаблонный (не тип) класс param, который может принимать любое перечисление?C ++ 11 - PullRequest
0 голосов
/ 28 февраля 2019

Вот фрагмент примера кода, который выполняет рекурсию по шаблонам.Я пытаюсь создать алгоритм, который принимает любое перечисление (из 0...n, последовательное) и выполняет «алгоритм» на основе этих значений, используя черты (делает это рекурсивно, вычитая наибольшее перечисление на 1).

#include <iostream>
using namespace std;

enum enum_type : size_t
{
    DEFAULT = 0,
    ONE = 1,
    TWO = 2,
    THREE = 3,
    FOUR = 4,
    MAX = FOUR,
};

template < enum_type F >
struct traits;

template < >
struct traits<ONE>
{
    static void do_something() {}
};

template < >
struct traits<TWO>
{
    static void do_something() {}
};

template < >
struct traits<THREE>
{
    static void do_something() {}
};

template < >
struct traits<FOUR>
{
    static void do_something() {}
};

template < enum_type F, typename TT = traits<F> >
struct attr_engine
{
    static void set()    {
        printf("Number: %lu ", F);

        TT::do_something();

        // get a compile error of trying to subtract an enum to an integer
        constexpr enum_type NEXT_FIELD = static_cast<enum_type>(F - 1);
        attr_engine<NEXT_FIELD>::set();
        return;
    }
};

template < >
struct attr_engine<DEFAULT, traits<DEFAULT>>
{
    static void set()    {
    printf("Reached the end");
    return;
    }
};

int main()
{
   attr_engine<MAX>::set();

   return 0;
}

Я хотел бы создать это в «универсальном» алгоритме, который может принимать любое перечисление (enum_type2 вместо только enum_type и т. Д.), Но я не совсем уверен, как это сделать.сделать это с нетиповыми параметрами шаблона, или это даже возможно.

Я не могу использовать typename, потому что я использую нетиповые параметры шаблона.

template < typename F, typename TT = traits<F> >
struct attr_engine

КакВ качестве альтернативы я подумал об использовании std::size_t потенциально:

template < size_t F, typename TT = traits<F> >
struct attr_engine

Но попытка создать обобщенный F, который можно вывести в соответствующую ему черту, - это то, на чем я застрял.Мне нужны новые подходы.Я боюсь, что из-за этого я приведу не входящий в шаблон параметр, который выглядит грязно.

enum enum_type2
{
    DEFAULT_ENUM2,
    ONE_VAL,
    TWO_VAL,
    THREE_VAL,
    FOUR_VAL,
    ENUM2_MAX = FOUR_VAL,
};

int main()
{
   attr_engine<static_cast<sizet>(ENUM2_MAX)>::set();

   return 0;

} ​​

1 Ответ

0 голосов
/ 28 февраля 2019

Я хотел бы создать это в «универсальном» алгоритме, который может принимать любое перечисление (enum_type2 вместо только enum_type и т. Д.), Но я не совсем уверен, как это сделать с нетиповым шаблономparams, или это даже возможно.

Вы пометили C ++ 11, поэтому вы не можете использовать auto в качестве параметра типа шаблона (доступно начиная с C ++ 17), поэтому у вас естьвыразить, как параметр типа шаблона, enum, который вы используете.

Лучшее, что я могу себе представить, это следующее

#include <iostream>

enum enum_type : std::size_t
 { DEFAULT = 0, ONE, TWO, THREE, FOUR, MAX = FOUR, };

enum enum_type2 : std::size_t
 { DEFAULTbis = 0, ONEbis, TWObis, THREEbis, MAXbis = THREEbis, };

template <typename ET, ET F>
struct traits
 { static void do_something() {} };

template <typename ET, ET F, typename TT = traits<ET, F>, typename = void>
struct attr_engine
 {
   static void set ()
    {
      std::cout << "Number: " << F << std::endl;

      TT::do_something();

      constexpr ET NEXT_FIELD = static_cast<ET>(F - 1u);
      attr_engine<ET, NEXT_FIELD>::set();
    }
 };

template <typename ET, ET F>
struct attr_engine<ET, F, traits<ET, F>,
                   typename std::enable_if<0u == F>::type>
 { static void set() { std::cout << "Reached the end" << std::endl; } };

int main ()
 {
   attr_engine<decltype(MAX), MAX>::set();
   attr_engine<decltype(MAXbis), MAXbis>::set();
 }

Если (когда) вы можете использовать C ++17, все становится проще

#include <iostream>

enum enum_type : std::size_t
 { DEFAULT = 0, ONE, TWO, THREE, FOUR, MAX = FOUR, };

enum enum_type2 : std::size_t
 { DEFAULTbis = 0, ONEbis, TWObis, THREEbis, MAXbis = THREEbis, };

template <auto>
struct traits
 { static void do_something() {} };

template <auto F, typename TT = traits<F>, typename = void>
struct attr_engine
 {
   static void set ()
    {
      std::cout << "Number: " << F << std::endl;

      TT::do_something();

      attr_engine<static_cast<decltype(F)>(F - 1u)>::set();
    }
 };

template <auto F>
struct attr_engine<F, traits<F>, typename std::enable_if<0u == F>::type>
 { static void set() { std::cout << "Reached the end" << std::endl; } };

int main ()
 {
   attr_engine<MAX>::set();
   attr_engine<MAXbis>::set();
 }
...