Переключатель типов во время выполнения для списков типов в качестве переключателя вместо вложенных if?

Это из ТТЛ:

////////////////////////////////////////////////////////////
//  run-time type switch
template <typename L, int N = 0, bool Stop=(N==length<L>::value) > struct type_switch;

template <typename L, int N, bool Stop>
  struct type_switch
  {
    template< typename F >
      void operator()( size_t i, F& f )
      {
        if( i == N )
        {
          f.operator()<typename impl::get<L,N>::type>();
        }
        else
        {
          type_switch<L, N+1> next;
          next(i, f);
        }
      }
  };

Он используется для переключения типов в TypeList. Вопрос в том, что они делают это с помощью ряда вложенных if. Есть ли способ сделать этот тип переключения вместо одного оператора выбора?

Спасибо!


person anon    schedule 28.01.2010    source источник
comment
Для чего на самом деле используется такая структура?   -  person Potatoswatter    schedule 28.01.2010
comment
Последняя версия clang может преобразовать такие вещи в таблицу переходов: godbolt.org/g/Nco0Al, GCC нельзя (с теми же параметрами): godbolt.org/g/4VL9e7.   -  person user877329    schedule 11.02.2017


Ответы (3)


Вам понадобится препроцессор для создания большого файла switch. Вам понадобится get<> для поиска вне границ без операций. Проверьте выходные данные компилятора, чтобы убедиться, что неиспользуемые случаи не производят никакого вывода, если вам это важно; при необходимости отрегулируйте ;v) .

Загляните в библиотеку препроцессоров Boost, если вы хотите добиться успеха в подобных вещах…

template <typename L>
  struct type_switch
  {
    template< typename F >
      void operator()( size_t i, F& f )
      {
        switch ( i ) {
         #define CASE_N( N ) \
         case (N): return f.operator()<typename impl::get<L,N>::type>();
         CASE_N(0)
         CASE_N(1)
         CASE_N(2)
         CASE_N(3) // ad nauseam.
      }
  };
person Potatoswatter    schedule 28.01.2010
comment
Если вы пойдете до тошноты, не будет ли это означать, что в какой-то момент коммутатор попытается создать экземпляр шаблона с потенциально недопустимым N, и все это не сможет скомпилироваться? Рекурсия знает, где остановиться, этот переключатель, по-видимому, не знает. (По сути, мне кажется, что вся идея переключения полностью ошибочна, а не является способом метапрограммирования шаблонов. IMO, переключатель времени компиляции - это не что иное, как цепочка if, созданная посредством рекурсии.) - person UncleBens; 28.01.2010
comment
@UncleBens: это то, что я имел в виду под поиском вне пределов без операций. Шаблон списка типов реализует рекурсию сам по себе в get<>; он должен обнаруживать выход за границы индекса и ничего не возвращать. Что касается преимущества перед цепочкой if, это зависит от компилятора и приложения. Согласно ответу на повторяющийся вопрос, boost::variant (намного более известный пример) использует описанную здесь технику. - person Potatoswatter; 29.01.2010
comment
Я просто хочу извиниться за то, что задал почти один и тот же вопрос дважды после вашего ответа. Проблема - сначала я не понял вашего ответа; но теперь, когда я это понимаю, я понимаю, почему мои другие вопросы были излишними. - person anon; 29.01.2010
comment
@anon: ничего страшного, я драматизировал, особенно потому что ситуация была забавной. Можно и вопросы задавать… - person Potatoswatter; 29.01.2010

Я так не думаю.

Этот тип метапрограммирования шаблонов обычно выполняется с помощью рекурсии. Поскольку все это происходит во время компиляции, я не удивлюсь, если во время выполнения не будет рекурсии или проверки условий.

person UncleBens    schedule 28.01.2010

Вы всегда можете использовать бинарный поиск вместо линейного поиска. Это было бы более сложно и с большей вероятностью содержало бы ошибки (бинарный поиск на удивление легко испортить).

Вы также можете вручную расширить N type_switch::operator(), где N — некоторая разумная верхняя граница количества длин списка типов, которые вы будете иметь в своей программе.

person MSN    schedule 28.01.2010