4 апр. 2010 г.

Template Magic Applied

Вот интересно что лучше: скрипт на Ruby, который генерирует:
    1 #ifndef __ENCODING__
    2 #define __ENCODING__
    3 
    4 template <typename T>
    5 struct encode_type {
    6     static const char code = '?';
    7 };
    8 
    9 template <typename T>
   10 struct encode_type<T *> {
   11     static const char code = '*';
   12 };
   13 
   14 template <>
   15 struct encode_type<char> {
   16     static const char code = 'c';
   17 };
   18 
   19 template <>
   20 struct encode_type<int> {
   21     static const char code = 'i';
   22 };
   23 
...

Или шаблонная магия:

    1 #include <cstdlib>
    2 #include <cstdio>
    3 #include <iostream>
    4 
    5 using namespace std;
    6 
    7 namespace Encodings {
    8  template <typename H, typename T>
    9  struct EL {
   10   typedef H Head;
   11   typedef T Tail;
   12  };
   13 
   14  template <typename T, char c>
   15  struct EP {
   16   typedef T Type;
   17   static const char code = c;
   18  };
   19 
   20  struct NullType;
   21 
   22  typedef EL<EP<int, 'i'>, EL<EP<char, 'c'>, EL<EP<float, 'f'>, EL<EP<double, 'd'>, EL<EP<bool, 'b'>, NullType> > > > > Encodings;
   23 
   24  template <typename List, typename T>
   25  struct EncFor {
   26   static const char result = 0;
   27  };
   28 
   29  template <typename T>
   30  struct EncFor<NullType, T> {
   31   static const char result = 0;
   32  };
   33 
   34  template <typename T, typename Tail, char c>
   35  struct EncFor<EL<EP<T, c>, Tail>, T> {
   36   static const char result = EP<T, c>::code;
   37  };
   38 
   39  template <typename T, typename Wrong, typename Tail, char c>
   40  struct EncFor<EL<EP<Wrong, c>, Tail>, T> {
   41   static const char result = EncFor<Tail, T>::result;
   42  };
   43 
   44  template <typename T>
   45  char encode_type(void) {
   46   return EncFor<Encodings, T>::result;
   47  }
   48 
   49  template <typename T>
   50  char encode_var_type(T t) {
   51   return encode_type<T>();
   52  }
   53 }
   54 
   55 int main(int argc, char **argv) {
   56  cout << Encodings::encode_type<int>() << endl;
   57 
   58  return EXIT_SUCCESS;
   59 }

Первое - проще осознать, проще дописать потом ещё тип, быстрее компилируется.
Второе - наркоманство, чтобы дописать ещё тип, надо осознать, долго компилируется. НО проще переделать все encoding'и, и нет внешнего генератора.
Мне больше нравится первый вариант, но отдельные личности против генерации кода внешней тулзой :( Интересно какой из вариантов попадет в release :)

2 комментария:

Unknown комментирует...

Что плохого во внешнем генераторе? Просто включаешь генерацию в макефайл, и спи спокойно... У сервера процессор от этого не расплавится. С другой стороны, мозг будет плавиться, когда будешь читать через год-два наркоманство с шаблонами.

Nekro.grave комментирует...

Ничего плохого, я так изначально и хотел. Проблема в том, что не у всех девелоперов есть ruby, одни мы с Иваном под линем.

А сервер тут совсем не при чем, код разработчики во время разработки все равно компилят. Не будешь же ты по каждому чиху commit делать. Впрочем я уже придумал как соптимизировать.

Моск плавится не сильно если осознать ФП.

Но вот похоже, что в релиз пойдут шаблоны, потому что ими удобно генерировать и таблицу cast'ов вида (char, char) -> cast-funcion-poiter. И вот тут шаблоны уже уместнее.