#include <iostream>

template <int Variables>
class Table {
  protected:
    int v[Variables];
  public:
    Table() {}
    virtual ~Table() {}
    int &operator[](const int i){return v[i];}
};

#define MAKE_TABLE(name, variables, aliases) \
struct name  : public Table<variables> { \
  protected: \
    typedef Table<variables> super_t; \
    typedef name self_t; \
    template <typename T, int Index> \
    struct AliasItem{ \
      static const int alias2index(const char *alias){ \
        return AliasItem<T, Index - 1>::alias2index(alias); \
      } \
    }; \
    template <typename T> \
    struct AliasItem<T, -1>{ \
      static const int alias2index(const char *alias){ \
        return -1; \
      } \
    }; \
  public: \
    name() : super_t() {} \
    ~name() {} \
    aliases \
  public: \
    static const int alias2index(const char *alias){ \
      return AliasItem<void, variables>::alias2index(alias); \
    } \
}
#define MAKE_ALIAS(name, i) \
public: \
  int &name(){return super_t::operator[](i);} \
protected: \
  template<typename T> \
  struct AliasItem<T, i> { \
    static const int alias2index(const char *alias){ \
      if(::strcmp(alias, #name) == 0){return i;} \
      else{return AliasItem<T, i - 1>::alias2index(alias);} \
    } \
  };

MAKE_TABLE(Test, 4, 
    MAKE_ALIAS(first, 0)
    MAKE_ALIAS(second, 1)
    MAKE_ALIAS(third, 2)
    MAKE_ALIAS(last, 3));

using namespace std;

int main() {
  Test test;

#define ASSIGN(name, v) \
cout << "alias (" << #name << ") is going to be asigned with " << v << endl; \
test.name() = v;
  
  ASSIGN(first, 1);
  ASSIGN(second, 2);
  ASSIGN(third, 3);
  ASSIGN(last, 4);
  
  const char *aliases[4]
      = {"first", "second", "third", "last"};
  for(unsigned i(0); i < 4; i++){
    cout << "The index of alias(" << aliases[i] << ") is " 
         << Test::alias2index(aliases[i])
         << ", and it is assigned with "
         << test[Test::alias2index(aliases[i])] << endl;
  }
  
  return 0;
}


