Re: Метапрограммирование C++ (RegExp)
От: Gluk_Kazan  
Дата: 06.11.07 07:33
Оценка:
Sorry, не разобрался с прикрепленными файлами


#pragma once
#include "TypeLists.h"
#include <memory>

namespace RegExp {

    enum ERROR_STATE {
        esNoError            = 0,
        esLimitError         = 1,
        esNoMatch            = 2,
        esOtherError         = 3
    };

    // Интерфейс результата разбора
    //////////////////////////////////////////////////////////////////////////////////////////////
    class CResIf
    { public:
        virtual ~CResIf() {}
        virtual void AddNode(CResIf* n) = 0;
        virtual void AddValue(const char* v, unsigned size = 0) = 0;
        virtual unsigned GetType(void) const = 0;
        virtual void SetParent(CResIf* p) {}
    };

    // Интерфейс интерпретатора регулярных выражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Match может выполняться несколько раз. При передаче src==NULL, продолжается поиск в строке
    //       использованной в предыдущем вызове
    // Reset сбрасывает результат поиска, что позволяет искать пересекающиеся диапазоны
    class CRegExpIf
    { public:
        virtual bool           Match(CResIf*& r, const char* src = NULL, unsigned size = 0) = 0;
        virtual const char*    Catch(unsigned level, unsigned& size) = 0;
        virtual ERROR_STATE  Replace(char* dst, unsigned size) = 0;
        virtual void           Reset(void) = 0;
        virtual CRegExpIf*     Clone(void) const = 0;
    };

    enum PREDICATE_TYPE {
        ptSpace              = 0,       // \s
        ptBegin              = 1,       // ^
        ptEnd                = 2,       // $
        ptSomeChar           = 3,       // .
        ptDigit              = 4,       // \d
        ptWordChar           = 5,       // \w
        ptWordBorder         = 6        // \b
    };

    enum QUANTIFIER_TYPE {
        qtGreed              = 0,
        qtLazy               = 1,
        qtFast               = 2
    };

    // Однократное сопоставление
    //////////////////////////////////////////////////////////////////////////////////////////////
    class O 
    { public:
        O(): IsOnce(true) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (!IsOnce) return -1;
          IsOnce = false;          
          return size;
        }
        const char* Catch(unsigned level, unsigned& size) { return NULL; }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) { return esOtherError; }
        void Clear(void) { IsOnce = true; }
      private:
        bool IsOnce;
    };

    // Последовательность подвыражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Должны быть последовательно выполнены все подвыражения
    //
    // 1. Вызывает Head.Match, пока не вернет -1 (для повтора квантификаторов)
    // 2. При неуспехе, вызывает Clear для Head и Tail
    template <class T> class E;
    template <> class E<NullType> 
    { public:
       int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) {return 0;} 
       const char* Catch(unsigned level, unsigned& size) { return NULL; }
       ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) {return esNoError;}
       void Clear(void) {}
    };
    template <class T, class U>
    class E< TypeList<T,U> > 
    { public:
        E(): Head(), Tail() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int Offset = 0;
          for (;;) {
              Offset = Head.Match(m,s,size,res);
              if (Offset<0) {
                  Clear();
                  return Offset;
              }
              int r = Tail.Match(m,s+Offset,size-Offset,res);
              if (r>=0) {
                  Offset += r;
                  break;
              }
          }
          return Offset;
        }
        const char* Catch(unsigned level, unsigned& size)
        { const char* r = Head.Catch(level,size);
          if (r==NULL)
              r = Tail.Catch(level,size);
          return r;
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { ERROR_STATE r = Head.Replace(m,dst,maxsize);
          if (r!=esNoError) return r;
          return Tail.Replace(m,dst,maxsize);
        }
        void Clear(void) 
        { Head.Clear();
          Tail.Clear();
        }
      private:
        T      Head;
        E< U > Tail;
    };
    template <class T> class E
    { public:
        E(): Elem() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { return Elem.Match(m,s,size,res);
        }
        const char* Catch(unsigned level, unsigned& size)
        { return Elem.Catch(level,size);
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { return Elem.Replace(m,dst,maxsize);
        }
        void Clear(void) 
        { Elem.Clear();
        }
      private:
        E< TL_1(T) > Elem;
    };

    // Дизъюнкция подвыражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Должно быть выполнено любое из подвыражений
    template <class T> class D;
    template <> class D<NullType> 
    { public:
       int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) {return -1;} 
       const char* Catch(unsigned level, unsigned& size) { return NULL; }
       void Clear(void) {}
    };
    template <class T, class U>
    class D< TypeList<T,U> > 
    { public:
        D(): Head(), Tail() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int r = Head.Match(m,s,size,res);
          if (r<0)
              r = Tail.Match(m,s,size,res);
          return r;
        }
        const char* Catch(unsigned level, unsigned& size)
        { const char* r = Head.Catch(level,size);
          if (r==NULL)
              r = Tail.Catch(level,size);
          return r;
        }
        void Clear(void) 
        { Head.Clear();
          Tail.Clear();
        }
      private:
        T      Head;
        D< U > Tail;
    };
    template <class T> class D
    { public:
        D(): Elem() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int r = Elem.Match(m,s,size,res);
          if (r<0) return 0;
          return r;
        }
        const char* Catch(unsigned level, unsigned& size)
        { return Elem.Catch(level,size);
        }
        void Clear(void) 
        { Elem.Clear();
        }
      private:
        T Elem;
    };

    // Квантификатор
    //////////////////////////////////////////////////////////////////////////////////////////////
    // Проверка r==0 после Elem.Match предназначена для определения утверждений нулевой ширины 
    // под квантификатором
    template <class T, class U = NullType, int mn = 0, int mx = 0, QUANTIFIER_TYPE t = qtFast>
    class Q
    { public:
        Q(): Elem(), Stop(), Cnt(-1) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { return Match(m,s,size,res,Int2Type<t>());
        }
        const char* Catch(unsigned level, unsigned& size)
        { return Elem.Catch(level,size);
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { for (int i=0;i<mn;i++) {
               ERROR_STATE r = Elem.Replace(m,dst,maxsize);
               if (r!=esNoError) return r;
          }
          return esNoError;
        }
        void Clear(void) 
        { Elem.Clear();
        }
      private:
        template <class S>
        int StopCond(CRegExpIf* m, const char* s, unsigned size, Type2Type<S>)
        { CResIf* r = NULL;
          Stop.Clear();
          return Stop.Match(m,s,size,r);
        }
        template <>
        int StopCond(CRegExpIf* m, const char* s, unsigned size, Type2Type<NullType>)
        { return -1;
        }
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res, Int2Type<qtGreed>)
        { unsigned Offset = 0;
          if (Cnt<0) {
              for (Cnt=0;;) {
                   int r = StopCond(m,s+Offset,size-Offset,Type2Type<U>());
                   if (r>=0) break;
                   Elem.Clear();
                   r = Elem.Match(m,s+Offset,size-Offset,res);
                   if (r<0) return break;
                   Cnt++;
                   Offset += r;
                   if (mx>0)
                       if (Cnt>=mx) break;
              }
              if (Cnt<mn) return -1;
              return Offset;
          }
          if (Cnt<=mn) return -1;
          Cnt--;
          for (int i=0;i<Cnt;i++) {
              Elem.Clear();
              int r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<0) return -1;
              Offset += r;
          }
          return Offset;
        }        
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res, Int2Type<qtLazy>)
        { unsigned Offset = 0;
          if (mx>0)
              if (Cnt>=mx) return -1;
          for (int i=0;i<Cnt;i++) {
              Elem.Clear();
              int r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<0) return -1;
              Offset += r;
          }
          for (;;) {
              int r = StopCond(m,s+Offset,size-Offset,Type2Type<U>());
              if (r>=0) break;
              Elem.Clear();
              r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<=0) break;
              if (Cnt<0) Cnt = 0;
              Cnt++;
              Offset += r;
              if (mx>0)
                  if (Cnt>=mx) break;
          }
          if (Cnt==0) return -1;
          if (Cnt<0)  Cnt = 0;
          if (Cnt<mn) return -1;
          return Offset;
        }        
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res, Int2Type<qtFast>)
        { unsigned Offset = 0;
          if (Cnt>=0) return -1;
          for (Cnt=0;;) {
              int r = StopCond(m,s+Offset,size-Offset,Type2Type<U>());
              if (r>=0) break;
              Elem.Clear();
              r = Elem.Match(m,s+Offset,size-Offset,res);
              if (r<=0) break;
              Cnt++;
              Offset += r;
              if (mx>0)
                  if (Cnt>=mx) break;
          }
          if (Cnt<mn) return -1;
          return Offset;
        }        
        E< T > Elem;
        U      Stop;
        int    Cnt;
    };

    // Захват
    //////////////////////////////////////////////////////////////////////////////////////////////
    template <class T> class B
    { public:
        B(): Elem(), Start(NULL), Size(0) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { Clear();
          int r = Elem.Match(m,s,size,res);
          if (r>=0) {
              Start = s;
              Size  = size;
              if (res!=NULL)
                  res->AddValue(s,Size);
          }
          return r;
        }
        const char* Catch(unsigned level, unsigned& size)
        { if (level==0) {
              size = Size;
              return Start;
          }
          return Elem.Catch(level-1,size);
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { return Elem.Replace(m,dst,maxsize);
        }
        void Clear(void)
        { Start = NULL;
          Size  = 0;
        }
      private:
        E< T >      Elem;
        const char* Start;
        unsigned    Size;
    };

    // Предикат
    //////////////////////////////////////////////////////////////////////////////////////////////
    // f задает инверсию предиката
    template <PREDICATE_TYPE p, bool f = false> class P;
    template <bool f> class P<ptSpace,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (s[0]==' ')  r = 1;
          if (s[0]==0x09) r = 1;
          if (s[0]==0x0A) r = 1;
          if (s[0]==0x0D) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> class P<ptBegin,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          if (O::Match(m,s,0,res)<0) return -1;
          const char* str = m->Catch(0,sz);
          if (str==NULL) return -1;
          int r = -1;
          if (str==s) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> 
    class P<ptEnd,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (O::Match(m,s,0,res)<0) return -1;
          if (size==0) return f?-1:0;
          return f?0:-1;
        }
    };
    template <bool f> class P<ptSomeChar,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (f) return -1;
          return 1;
        }
    };
    template <bool f> class P<ptDigit,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if ((s[0]>='0')&&(s[0]<='9')) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> class P<ptWordChar,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (s[0]=='_') r = 1;
          if ((s[0]>='a')&&(s[0]<='z'))         r = 1;
          if ((s[0]>='A')&&(s[0]<='Z'))         r = 1;
          if ((s[0]>='а')&&(s[0]<='я'))         r = 1;
          if ((s[0]>='А')&&(s[0]<='Я'))         r = 1;
          if ((s[0]=='ё')||(s[0]=='Ё'))         r = 1;
          if (P<ptDigit>().Match(m,s,1,res)==1) r = 1;
          if (f) r = -r;
          return r;
        }
    };
    template <bool f> class P<ptWordBorder,f>: public O
    { public:
        P(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          if (O::Match(m,s,0,res)<0) return -1;
          if (size==0) return f?-1:0;
          const char* str = m->Catch(0,sz);
          if (str==NULL) return -1;
          if (str==s) return f?-1:0;
          const char* p = s-1;
          if ((P<ptWordChar>().Match(m,p,1,res)==1)&&
              (P<ptWordChar>().Match(m,s,1,res)!=1)) return f?-1:0;
          if ((P<ptWordChar>().Match(m,p,1,res)!=1)&&
              (P<ptWordChar>().Match(m,s,1,res)==1)) return f?-1:0;
          return f?0:-1;
        }
    };

    // Диапазон символов
    //////////////////////////////////////////////////////////////////////////////////////////////
    // f задает инверсию диапазона
    template <int start,int end = 0, bool f = false> 
    class C: public O
    { public:
        C(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { int r = 1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if (s[0]<start) r = -1;
          if (end>start) {
              if (s[0]>end) r = -1;
          } else {
              if (s[0]>start) r = -1;
          }
          if (f) r = -r;
          return r;
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { if (maxsize<1) return esLimitError;
          if ((end!=0)&&(start!=end)) return esOtherError;
          dst[0] = start;
          dst++;
          maxsize--;
          return esNoError;
        }
    };

    // Символьный набор
    //////////////////////////////////////////////////////////////////////////////////////////////
    // f задает инверсию набора
    template <class T, bool f = false> class S;
    template <bool f> class S<NullType,f> 
    { public:
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { return true; 
        } 
    };
    template <class T, class U, bool f>
    class S< TypeList<T,U>, f>: public O
    { public:
        S< TypeList<T,U>, f>(): O(), Head(), Tail() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { int r = -1;
          if (size==0) return -1;
          if (O::Match(m,s,1,res)<0) return -1;
          if ((Head.Match(m,s,1,res)==1)||
              (Tail.Match(m,s,1,res)==1)) r = 1;
          if (f) r = -r;
          return r;
        }
      private:
        T       Head;
        S< U >  Tail;
    };
    template <class T, bool f>
    class S
    { public:
        S(): Elem() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res) 
        { return Elem.Match(m,s,size,res);
        }
      private:
        S<TL_1(T),f> Elem;
    };

    // Переменная
    //////////////////////////////////////////////////////////////////////////////////////////////
    template <int level> 
    class V: public O
    { public:
        V(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { unsigned sz;
          const char* v = m->Catch(level,sz);
          if (v==NULL) return -1;
          if (sz>size) return -1;
          if (memcmp(s,v,sz)==0) return sz;
          return -1;
        }
        ERROR_STATE Replace(CRegExpIf* m, char*& dst, unsigned& maxsize) 
        { unsigned sz;
          const char* v = m->Catch(level);
          if (v==NULL) return esNoMatch;
          if (sz>maxsize) return esLimitError;
          memcpy(dst,v,sz);
          dst += sz;
          maxsize -= sz;
          return esNoError; 
        }
    };

    // Рекурсивное применение выражения
    //////////////////////////////////////////////////////////////////////////////////////////////
    template <class T = NullType, class U = NullType> class R;
    template <>
    class R<NullType,NullType>: public O
    { public:
        R(): O() {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { if (size==0) return 0;
          std::auto_ptr<CRegExpIf> p(m->Clone());
          return p->Match(res,s,size);
        }
    };
    template <class T, class U>
    class R: public CRegExpIf,
             public O
    { public: 
        R(): CRegExpIf(), Elem(), Found(-1) {}
        int Match(CRegExpIf* m, const char* s, unsigned size, CResIf*& res)
        { Match(res,s,size);
          return Found;
        }
        virtual bool Match(CResIf*& r, const char* src = NULL, unsigned size = 0)
        { CreateNode(r,Type2Type<U>());
          Found = Elem.Match(this,src,size,r);
          return (Found>=0);
        }
        virtual const char* Catch(unsigned level, unsigned& size) {return NULL;}
        virtual ERROR_STATE Replace(char* dst, unsigned size) {return esOtherError;}
        virtual void Reset(void) {}
        virtual CRegExpIf* Clone(void) const { return new R<T,U>; }
      private:
        template <class S>
        void CreateNode(CResIf*& r, Type2Type<S>)
        { CResIf* p = new S;
          if (r!=NULL) r->AddNode(p);
          r = p;
        }
        template <>
        void CreateNode(CResIf*& r, Type2Type<NullType>) {}
        E< T > Elem;
        int    Found;
    };

    // Интерпретатор регулярных выражений
    //////////////////////////////////////////////////////////////////////////////////////////////
    template < class T, class U = NullType>
    class CRegExp: public CRegExpIf
    { public:
        CRegExp(): Expr(), Repl(), Start(NULL), Str(NULL), Size(0), Found(-1) {}

        virtual bool           Match(CResIf*& r, const char* src = NULL, unsigned size = 0);
        virtual const char*    Catch(unsigned level, unsigned& size);
        virtual ERROR_STATE  Replace(char* dst, unsigned size);
        virtual void           Reset(void) { Found = -1; }
        virtual CRegExpIf*     Clone(void) const { return new CRegExp<T,U>; }

      private:
        E< T >       Expr;
        E< U >       Repl;
        const char*  Start;
        const char*  Str;
        unsigned     Size;

      public:
        int          Found;
    };

    template <class T, class U>
    bool CRegExp<T,U>::Match(CResIf*& r, const char* src, unsigned size) 
    { 
      if (src!=NULL) {
          Str   = src;
          Start = src;    
          Size  = size;
          if (Size==0) 
              Size = (unsigned)strlen(src);
      } else {
          if (Str==NULL) return false;
          int step = (Found<=0)?1:Found;
          if (Size<=(unsigned)step) return false;
          Str  += step;
          Size -= step;
      }
      Reset();
      while ((Found=Expr.Match(this,Str,Size,r))==-1) {
          if (Size<=1) return false;
          Str++;
          Size--;
      }
      return true;
    }

    template <class T, class U>
    ERROR_STATE CRegExp<T,U>::Replace(char* dst, unsigned size)
    { return Repl.Replace(this,dst,size);
    }

    template <class T, class U>
    const char* CRegExp<T,U>::Catch(unsigned level, unsigned& size)
    {
      if (level==0) {
          size = (Found<0)?Size:Found;
          return (Found<0)?Start:Str;
      }
      return Expr.Catch(level-1,size);
    }

}



#pragma once
#include "RegExp.h"

namespace RegExp {

typedef C<'0','9'>                                   Digit;
typedef C<'A','F'>                                   HexUpper;
typedef C<'a','f'>                                   HexLower;
typedef D_2(HexUpper, HexLower)                      Hex;
typedef C<'0','1'>                                   Max1w0;
typedef C<'0','2'>                                   Max2w0;
typedef C<'0','4'>                                   Max4w0;
typedef C<'0','5'>                                   Max5w0;
typedef C<'1','2'>                                   Max2;
typedef C<'0','5'>                                   Max5;

// Короткая форма представления сетевой маски
typedef E_2(Max2, Digit)                             Octet29;
typedef E_2(C<3>, Max2w0)                            Octet32;
typedef D_3(Digit, Octet29, Octet32)                 IPMaskShort;

typedef Q<Max1w0, NullType, 0, 1>                    IPForm1p1;
typedef Q<Digit,  NullType, 0, 1>                    IPForm1p2;
typedef E_3(IPForm1p1, Digit, IPForm1p2)             IPForm1;
typedef E_3(C<'2'>, Max4w0, Digit)                   IPForm2;
typedef E_3(C<'2'>, C<'5'>, Max5w0)                  IPForm3;
typedef B< D_3(IPForm1, IPForm2, IPForm3) >          IPOctet;
typedef Q< E_2(C<'.'>, IPOctet), NullType, 3, 3 >    IPTail;
typedef E_2(IPOctet, IPTail)                         IPAddress;

// Mac-адрес
typedef B< Q<Hex, NullType, 2, 2> >                  MacOctet;
typedef Q< E_2(C<':'>, MacOctet), NullType, 5, 5 >   MacTail;
typedef E_2(MacOctet, MacTail)                       MacAddress;

}



#pragma once

class NullType {};

template <int n>
struct Int2Type
{
    enum { value = n };
};

template <class T>
struct Type2Type
{
    typedef T result;
};

template <class T, class U>
struct TypeList
{
    typedef T Head;
    typedef U Tail;
};

#define TL_1(T1) TypeList<T1, NullType >
#define TL_2(T1, T2) TypeList<T1, TL_1(T2) >
#define TL_3(T1, T2, T3) TypeList<T1, TL_2(T2, T3) >
#define TL_4(T1, T2, T3, T4) TypeList<T1, TL_3(T2, T3, T4) >
#define TL_5(T1, T2, T3, T4, T5) TypeList<T1, TL_4(T2, T3, T4, T5) >
#define TL_6(T1, T2, T3, T4, T5, T6) TypeList<T1, TL_5(T2, T3, T4, T5, T6) >
#define TL_7(T1, T2, T3, T4, T5, T6, T7) TypeList<T1, TL_6(T2, T3, T4, T5, T6, T7) >
#define TL_8(T1, T2, T3, T4, T5, T6, T7, T8) TypeList<T1, TL_7(T2, T3, T4, T5, T6, T7, T8) >
#define TL_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) TypeList<T1, TL_8(T2, T3, T4, T5, T6, T7, T8, T9) >
#define TL_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) TypeList<T1, TL_9(T2, T3, T4, T5, T6, T7, T8, T9, T10) >

#define C_1(C1) E<TL_1(C<'C1'>) >
#define C_2(C1, C2) E<TL_2(C<'C1'>,C<'C2'>) >
#define C_3(C1, C2, C3) E<TL_3(C<'C1'>,C<'C2'>,C<'C3'>) >
#define C_4(C1, C2, C3, C4) E<TL_4(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>) >
#define C_5(C1, C2, C3, C4, C5) E<TL_5(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>) >
#define C_6(C1, C2, C3, C4, C5, C6) E<TL_6(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>) >
#define C_7(C1, C2, C3, C4, C5, C6, C7) E<TL_7(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>) >
#define C_8(C1, C2, C3, C4, C5, C6, C7, C8) E<TL_8(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>,C<'C8'>) >
#define C_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) E<TL_9(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>,C<'C8'>,C<'C9'>) >
#define C_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) E<TL_10(C<'C1'>,C<'C2'>,C<'C3'>,C<'C4'>,C<'C5'>,C<'C6'>,C<'C7'>,C<'C8'>,C<'C9'>,C<'C10'>) >

#define E_1(C1) E< C1 >
#define E_2(C1, C2) E< TL_2(C1, C2) >
#define E_3(C1, C2, C3) E< TL_3(C1, C2, C3) >
#define E_4(C1, C2, C3, C4) E< TL_4(C1, C2, C3, C4) >
#define E_5(C1, C2, C3, C4, C5) E< TL_5(C1, C2, C3, C4, C5) >
#define E_6(C1, C2, C3, C4, C5, C6) E< TL_6(C1, C2, C3, C4, C5, C6) >
#define E_7(C1, C2, C3, C4, C5, C6, C7) E< TL_7(C1, C2, C3, C4, C5, C6, C7) >
#define E_8(C1, C2, C3, C4, C5, C6, C7, C8) E< TL_8(C1, C2, C3, C4, C5, C6, C7, C8) >
#define E_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) E< TL_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) >
#define E_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) E< TL_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) >

#define D_1(C1) D< C1 >
#define D_2(C1, C2) D< TL_2(C1, C2) >
#define D_3(C1, C2, C3) D< TL_3(C1, C2, C3) >
#define D_4(C1, C2, C3, C4) D< TL_4(C1, C2, C3, C4) >
#define D_5(C1, C2, C3, C4, C5) D< TL_5(C1, C2, C3, C4, C5) >
#define D_6(C1, C2, C3, C4, C5, C6) D< TL_6(C1, C2, C3, C4, C5, C6) >
#define D_7(C1, C2, C3, C4, C5, C6, C7) D< TL_7(C1, C2, C3, C4, C5, C6, C7) >
#define D_8(C1, C2, C3, C4, C5, C6, C7, C8) D< TL_8(C1, C2, C3, C4, C5, C6, C7, C8) >
#define D_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) D< TL_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) >
#define D_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) D< TL_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) >

#define S_1(C1) S< C1 >
#define S_2(C1, C2) S< TL_2(C1, C2) >
#define S_3(C1, C2, C3) S< TL_3(C1, C2, C3) >
#define S_4(C1, C2, C3, C4) S< TL_4(C1, C2, C3, C4) >
#define S_5(C1, C2, C3, C4, C5) S< TL_5(C1, C2, C3, C4, C5) >
#define S_6(C1, C2, C3, C4, C5, C6) S< TL_6(C1, C2, C3, C4, C5, C6) >
#define S_7(C1, C2, C3, C4, C5, C6, C7) S< TL_7(C1, C2, C3, C4, C5, C6, C7) >
#define S_8(C1, C2, C3, C4, C5, C6, C7, C8) S< TL_8(C1, C2, C3, C4, C5, C6, C7, C8) >
#define S_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) S< TL_9(C1, C2, C3, C4, C5, C6, C7, C8, C9) >
#define S_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) S< TL_10(C1, C2, C3, C4, C5, C6, C7, C8, C9, C10) >
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.