Как отменить пакет целочисленных параметров? - PullRequest
0 голосов
/ 04 ноября 2018

К сожалению, я не могу использовать ни одну из / библиотек из C ++, потому что я программирую для встроенной операционной системы, которая имеет только доступные 4.4.4 с чистым C ++, поэтому нет std::tuple, std::forward, std::apply или std::anything_else.

Чтобы помочь понять сгенерированный мета-общий код, я представляю минимальный пример кода, скомпилированного с , потому что у него есть возможность показать нам сгенерированный / код.

Этот вопрос только для любопытства, потому что вместо генерации целочисленного пакета параметров в неправильном порядке, я могу просто создать его в правильном порядке. Это то, что я использую для создания целочисленной упаковки в неправильном порядке:

template<int ...>
struct MetaSequenceOfIntegers { };

template<int AccumulatedSize, typename Tn, int... GeneratedSequence>
struct GeneratorOfIntegerSequence;

template<int AccumulatedSize, typename Grouper, typename Head, typename... Tail, int... GeneratedSequence>
struct GeneratorOfIntegerSequence< AccumulatedSize, Grouper( Head, Tail... ), GeneratedSequence... >
{
    typedef typename GeneratorOfIntegerSequence
            < AccumulatedSize + sizeof(Head), Grouper( Tail... ), AccumulatedSize, GeneratedSequence...
            >::type type;
};

template<int AccumulatedSize, typename Grouper, int... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(), GeneratedSequence...>
{
  typedef MetaSequenceOfIntegers<GeneratedSequence...> type;
};

template<int ...Sequence>
void intergers_sequencer_generator(MetaSequenceOfIntegers<Sequence...>) {
    int array[] = {Sequence...};
}

int main(int argc, char const *argv[]) {
    intergers_sequencer_generator( GeneratorOfIntegerSequence< 0, int(char, int, char) >::type() );
    return 0;
}

Я использую только int array[] = {Sequence...} для демонстрации. Используемый реальный код выглядит так:

template<typename ReturnType, typename... Tn>
class Closure
{ 
    // ... other code
    template<int ...Sequence>
    ReturnType _run(MetaSequenceOfIntegers<Sequence...>) {
        return _function_entry_pointer( get_nth_function_argument_on_address<Sequence, Tn>()... );
    }
    // ... other code
}

, который генерирует этот сильфон, для ввода типа create_functor( &function1, 'a', 10, 'b' ):

template <int ...Sequence> char _run(MetaSequenceOfIntegers<Sequence...>);
template<> char _run<<5, 1, 0>>(MetaSequenceOfIntegers<5, 1, 0>)     {
    return this->_function_entry_pointer(
            this->get_nth_function_argument_on_address<5, const char *>(), 
            this->get_nth_function_argument_on_address<1, const char *>(), 
            this->get_nth_function_argument_on_address<0, char>()
        );
}
// and much more

Мы можем увидеть сгенерированный код, используя :

$ clang++ -Xclang -ast-print -fsyntax-only generator.cpp > expanded.cpp

template <int ...> struct MetaSequenceOfIntegers {
};
template<> struct MetaSequenceOfIntegers<<5, 1, 0>> {
};
template <int AccumulatedSize, typename Tn, int ...GeneratedSequence> struct GeneratorOfIntegerSequence
template<> struct GeneratorOfIntegerSequence<0, int (char, int, char), <>> {
    typedef typename GeneratorOfIntegerSequence<0 + sizeof(char), int (int, char), 0>::type type;
}
template<> struct GeneratorOfIntegerSequence<1, int (int, char), <0>> {
    typedef typename GeneratorOfIntegerSequence<1 + sizeof(int), int (char), 1, 0>::type type;
}
template<> struct GeneratorOfIntegerSequence<5, int (char), <1, 0>> {
    typedef typename GeneratorOfIntegerSequence<5 + sizeof(char), int (), 5, 1, 0>::type type;
}
template<> struct GeneratorOfIntegerSequence<6, int (), <5, 1, 0>> {
    typedef MetaSequenceOfIntegers<5, 1, 0> type;
};
template <int AccumulatedSize, typename Grouper, typename Head, typename ...Tail, int ...GeneratedSequence> struct GeneratorOfIntegerSequence<AccumulatedSize, type-parameter-0-1 (type-parameter-0-2, type-parameter-0-3...), <GeneratedSequence...>> {
    typedef typename GeneratorOfIntegerSequence<AccumulatedSize + sizeof(Head), Grouper (Tail...), AccumulatedSize, GeneratedSequence...>::type type;
};
template <int AccumulatedSize, typename Grouper, int ...GeneratedSequence> struct GeneratorOfIntegerSequence<AccumulatedSize, type-parameter-0-1 (), <GeneratedSequence...>> {
    typedef MetaSequenceOfIntegers<GeneratedSequence...> type;
};
template <int ...Sequence> void intergers_sequencer_generator(MetaSequenceOfIntegers<Sequence...>) {
    int array[] = {Sequence...};
}
template<> void intergers_sequencer_generator<<5, 1, 0>>(MetaSequenceOfIntegers<5, 1, 0>) {
    int array[] = {5, 1, 0};
}
int main(int argc, const char *argv[]) {
    intergers_sequencer_generator(GeneratorOfIntegerSequence<0, int (char, int, char)>::type());
    return 0;
}

Список метапрограммирования генерируется в обратном порядке. Вместо int array[] = {5, 1, 0} должно быть int array[] = {0, 1, 5}.

Мне удалось сформировать список в правильном порядке, просто изменив эту строку в примере кода:

< AccumulatedSize + sizeof(Head), Grouper( Tail... ), GeneratedSequence..., AccumulatedSize
// to -->
< AccumulatedSize + sizeof(Head), Grouper( Tail... ), AccumulatedSize, GeneratedSequence...

Но давайте предположим, что я не мог этого сделать, потому что список является входом из третьей части, которую я не могу контролировать. Как я могу изменить пакет параметров <5, 1, 0> на <0, 1, 5> без использования каких-либо функций библиотеки std?

В моей первой попытке я попытался использовать ту же стратегию, что и я, для генерации целочисленного списка, но я не смог его скомпилировать:

template<int ...>
struct MetaSequenceOfIntegers { };

template<int AccumulatedSize, typename Tn, int... GeneratedSequence>
struct GeneratorOfIntegerSequence;

template<int AccumulatedSize, typename Grouper, typename Head, typename... Tail, int... GeneratedSequence>
struct GeneratorOfIntegerSequence< AccumulatedSize, Grouper( Head, Tail... ), GeneratedSequence... >
{
    typedef typename GeneratorOfIntegerSequence
            < AccumulatedSize + sizeof(Head), Grouper( Tail... ), AccumulatedSize, GeneratedSequence...
            >::type type;
};

template<int AccumulatedSize, typename Grouper, int... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(), GeneratedSequence...>
{
  typedef MetaSequenceOfIntegers<GeneratedSequence...> type;
};

// The new code starts here
template<int ...>
struct MetaSequenceReversed { };

template<typename Tn, int... GeneratedSequence>
struct ReversorOfIntegerSequence;

template<typename Grouper, int Head, int... Tail, int... GeneratedSequence>
struct ReversorOfIntegerSequence< Grouper( Head, Tail... ), GeneratedSequence... >
{
    typedef typename ReversorOfIntegerSequence
            < Grouper( Tail... ), GeneratedSequence...
            >::type type;
};

template<typename Grouper, int... GeneratedSequence>
struct ReversorOfIntegerSequence<Grouper(), GeneratedSequence...>
{
  typedef MetaSequenceReversed<GeneratedSequence...> type;
};

template<int ...ReversedSequence>
void intergers_sequencer_reversor(MetaSequenceReversed<ReversedSequence...>) {
    int reversed_array[] = {ReversedSequence...};
}

template<int ...Sequence>
void intergers_sequencer_generator(MetaSequenceOfIntegers<Sequence...>) {
    int array[] = {Sequence...};
    intergers_sequencer_reversor( ReversorOfIntegerSequence< int(Sequence...) >::type() );
}

int main(int argc, char const *argv[])
{
    intergers_sequencer_generator( GeneratorOfIntegerSequence< 0, int(char, int, char) >::type() );
    return 0;
}

Когда я пытаюсь построить это, я получаю эту ошибку:

generator.cpp:29:35: error: template argument for template type parameter must be a type
struct ReversorOfIntegerSequence< Grouper( Head, Tail... ), GeneratedSequence... >
                                  ^~~~~~~~~~~~~~~~~~~~~~~~
generator.cpp:25:19: note: template parameter is declared here
template<typename Tn, int... GeneratedSequence>
                  ^
generator.cpp:50:62: error: template argument for template type parameter must be a type
    intergers_sequencer_reversor( ReversorOfIntegerSequence< int(Sequence...) >::type() );
                                                             ^~~~~~~~~~~~~~~~
generator.cpp:25:19: note: template parameter is declared here
template<typename Tn, int... GeneratedSequence>
                  ^

Ссылки:

  1. Вариативные шаблоны, пакет параметров и обсуждаемая неоднозначность в списке параметров
  2. "распаковка" кортежа для вызова соответствующего указателя функции
  3. Можем ли мы увидеть шаблонный экземпляр шаблона с помощью компилятора C ++
  4. Параметры функции построения с помощью шаблонов с переменными значениями
  5. Как поменять порядок аргументов переменной функции шаблона?

1 Ответ

0 голосов
/ 05 ноября 2018

Как изменить параметр pack <5, 1, 0> на <0, 1, 5> без использования функций библиотеки std?

Не уверен, что понимаю, что именно ты можешь использовать, но ... мне кажется, это просто.

С учетом вспомогательной структуры следующим образом

template <typename, typename>
struct RS_helper;

template <int ... As, int B0, int ... Bs>
struct RS_helper<MetaSequenceOfIntegers<As...>,
                 MetaSequenceOfIntegers<B0, Bs...>>
   : RS_helper<MetaSequenceOfIntegers<B0, As...>,
               MetaSequenceOfIntegers<Bs...>>
 { };

template <typename T>
struct RS_helper<T, MetaSequenceOfIntegers<>>
 { using type = T; };

Возвратная структура может быть просто

template <int ... Is>
struct RevertSequence
   : RS_helper<MetaSequenceOfIntegers<>, MetaSequenceOfIntegers<Is...>>
 { };

Я полагаю, что обратная функция может быть полезна

template <int ... Is>
constexpr typename RevertSequence<Is...>::type
   revertSequenceFunction (MetaSequenceOfIntegers<Is...> const &)
 { return {}; }

Я предлагаю модифицированную версию вашего исходного кода с добавлением обратной последовательности (также используйте std::cout для печати последовательностей, но вы можете удалить ее, очевидно).

#include <iostream>

template <int ...>
struct MetaSequenceOfIntegers
 { };

template <int AccumulatedSize, typename Tn, int ... GeneratedSequence>
struct GeneratorOfIntegerSequence;

template <int AccumulatedSize, typename Grouper, typename Head,
          typename ... Tail, int ... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(Head, Tail...),
                                  GeneratedSequence... >
 { typedef typename GeneratorOfIntegerSequence
            <AccumulatedSize+sizeof(Head), Grouper(Tail...),
             AccumulatedSize, GeneratedSequence...>::type type; };

template <int AccumulatedSize, typename Grouper, int ... GeneratedSequence>
struct GeneratorOfIntegerSequence<AccumulatedSize, Grouper(),
                                  GeneratedSequence...>
 { typedef MetaSequenceOfIntegers<GeneratedSequence...> type; };

template <int ... Sequence>
void intergers_sequencer_generator(MetaSequenceOfIntegers<Sequence...>)
 {
   using unused = int[];

   (void)unused { 0, (std::cout << Sequence << ' ', 0)... };

   std::cout << std::endl;
 }


template <typename, typename>
struct RS_helper;

template <int ... As, int B0, int ... Bs>
struct RS_helper<MetaSequenceOfIntegers<As...>,
                 MetaSequenceOfIntegers<B0, Bs...>>
   : RS_helper<MetaSequenceOfIntegers<B0, As...>,
               MetaSequenceOfIntegers<Bs...>>
 { };

template <typename T>
struct RS_helper<T, MetaSequenceOfIntegers<>>
 { using type = T; };

template <int ... Is>
struct RevertSequence
   : RS_helper<MetaSequenceOfIntegers<>, MetaSequenceOfIntegers<Is...>>
 { };

template <int ... Is>
constexpr typename RevertSequence<Is...>::type
   revertSequenceFunction (MetaSequenceOfIntegers<Is...> const &)
 { return {}; }

int main ()
 {
   intergers_sequencer_generator(
      GeneratorOfIntegerSequence<0, int(char, int, char)>::type());

   intergers_sequencer_generator(
      revertSequenceFunction(
         GeneratorOfIntegerSequence<0, int(char, int, char)>::type()));
 }
...