int main()
{
// Hello, World! in Brainf*ck (from wikipedia):
/*
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set the next four cells to 70/100/30/10
> +++++ ++ add 7 to cell #1
> +++++ +++++ add 10 to cell #2
> +++ add 3 to cell #3
> + add 1 to cell #4
<<<< - decrement counter (cell #0)
]
> ++ . print 'H'
> + . print 'e'
+++++ ++ . print 'l'
. print 'l'
+++ . print 'o'
> ++ . print ' '
<< +++++ +++++ +++++ . print 'W'
> . print 'o'
+++ . print 'r'
----- - . print 'l'
----- --- . print 'd'
> + . print '!'
> . print '\n' */
// Template metaprogram translation
typedef typelist
<
inc,inc,inc,inc,inc, inc,inc,inc,inc,inc,
rep,
nxt, inc,inc,inc,inc,inc, inc,inc,
nxt, inc,inc,inc,inc,inc, inc,inc,inc,inc,inc,
nxt, inc,inc,inc,
nxt, inc,
prv,prv,prv,prv, dec,
end,
nxt, inc,inc, out,
nxt, inc, out,
inc,inc,inc,inc,inc, inc,inc, out,
out,
inc,inc,inc, out,
nxt, inc,inc, out,
prv,prv, inc,inc,inc,inc,inc, inc,inc,inc,inc,inc, inc,inc,inc,inc,inc, out,
nxt, out,
inc,inc,inc, out,
dec,dec,dec,dec,dec, dec, out,
dec,dec,dec,dec,dec, dec,dec,dec, out,
nxt, inc, out,
nxt, out
> program;
print< run<program>::out >();
std::cout << std::endl;
}
This outputs "Hello World!" when run. The string is computed at compile time by running that variadic template Brainf*ck metaprogram. Of course, you need a variadic template aware compiler, such as GCC version 4.4 and above to compile it.
The whole program is here:
#include <iostream>
//--------------------------------------------------------------
// Type List "Container"
//--------------------------------------------------------------
template <class...>
struct typelist; // GCC workaround
template <class Head, class... Tail>
struct typelist<Head, Tail...>
{
typedef Head head;
typedef typelist<Tail...> tail;
};
//--------------------------------------------------------------
// Cons for data
//--------------------------------------------------------------
template <char Head, class Tail>
struct dcons
{
static const char head = Head;
typedef Tail tail;
};
//--------------------------------------------------------------
// Data container (list of char)
//--------------------------------------------------------------
template <char...>
struct data; // GCC workaround
template <char Head, char... Tail>
struct data<Head, Tail...>
: dcons<Head, data<Tail...>> {};
//--------------------------------------------------------------
// Gets type N from typelist List.
//--------------------------------------------------------------
template <class List, int N>
struct at
{
typedef typename at<typename List::tail, N - 1>::ret ret;
};
template <class List>
struct at<List, 0>
{
typedef typename List::head ret;
};
//--------------------------------------------------------------
// Gets the char at data cell N from Data
//--------------------------------------------------------------
template <class Data, int N>
struct cell
{
static const char val = cell<typename Data::tail, N - 1>::val;
};
template <class Data>
struct cell<Data, 0>
{
static const char val = Data::head;
};
//--------------------------------------------------------------
// Data, but with cell N set to C
//--------------------------------------------------------------
template <class Data, int N, char C>
struct dset
: dcons<Data::head, dset<typename Data::tail, N - 1, C> > {};
template <class Data, char C>
struct dset<Data, 0, C>
: dcons<C, typename Data::tail> {};
//--------------------------------------------------------------
// Encapsulation of program state machine.
//--------------------------------------------------------------
template <class Prog, class Data, class Out, int PC, int DP>
struct state
{
typedef Prog prog; // The program (typelist)
typedef Data data; // The data
typedef Out out; // The output (data)
static const int pc = PC; // The program counter
static const int dp = DP; // The data pointer
static const char val = cell<data, dp>::val; // current value at dp
};
// Helper macros to avoid typename nonsense.
#define PROG(S) typename S::prog
#define DATA(S) typename S::data
#define OUT(S) typename S::out
//--------------------------------------------------------------
// Brainf*ck commands
//--------------------------------------------------------------
struct nxt {}; // move pointer right (next)
struct prv {}; // move pointer left (previous)
struct inc {}; // increment at pointer
struct dec {}; // decrement at pointer
struct out {}; // print character
struct rep {}; // while not 0 (repeat)
struct end {}; // end while
//--------------------------------------------------------------
// Next state after performing Cmd on S
//--------------------------------------------------------------
template <class S, class Cmd>
struct cmd { };
//--------------------------------------------------------------
// Performs move right command
//--------------------------------------------------------------
template <class S>
struct cmd<S, nxt>
: state<PROG(S), DATA(S), OUT(S), S::pc + 1, S::dp + 1> {};
//--------------------------------------------------------------
// Performs move left command
//--------------------------------------------------------------
template <class S>
struct cmd<S, prv>
: state<PROG(S), DATA(S), OUT(S), S::pc + 1, S::dp - 1> {};
//--------------------------------------------------------------
// Performs increment command
//--------------------------------------------------------------
template <class S>
struct cmd<S, inc>
: state<PROG(S), dset<DATA(S), S::dp, S::val + 1>, OUT(S), S::pc + 1, S::dp> {};
//--------------------------------------------------------------
// Performs decrement command
//--------------------------------------------------------------
template <class S>
struct cmd<S, dec>
: state<PROG(S), dset<DATA(S), S::dp, S::val - 1>, OUT(S), S::pc + 1, S::dp> {};
//--------------------------------------------------------------
// Performs output command
//--------------------------------------------------------------
template <class S>
struct cmd<S, out>
: state<PROG(S), DATA(S), dcons<S::val, OUT(S)>, S::pc + 1, S::dp> {};
//--------------------------------------------------------------
// Performs while loop command
//--------------------------------------------------------------
template <class P, int PC>
struct fwd_jmp;
template <class P, int PC, class Cmd>
struct fwd_jmp_impl
: fwd_jmp<P, PC + 1> {};
template <class P, int PC>
struct fwd_jmp_impl<P, PC, rep>
: fwd_jmp<P, fwd_jmp<P, PC + 1>::ret> {};
template <class P, int PC>
struct fwd_jmp_impl<P, PC, end>
{
static const int ret = PC + 1;
};
template <class P, int PC>
struct fwd_jmp
: fwd_jmp_impl<P, PC, typename at<P, PC>::ret> {};
template <class S, bool Done>
struct cmd_rep
: state<PROG(S), DATA(S), OUT(S), fwd_jmp<PROG(S), S::pc + 1>::ret, S::dp> {};
template <class S>
struct cmd_rep<S, false>
: state<PROG(S), DATA(S), OUT(S), S::pc + 1, S::dp> {};
template <class S>
struct cmd<S, rep>
: cmd_rep<S, S::val == 0> {};
//--------------------------------------------------------------
// Performs end loop command
//--------------------------------------------------------------
template <class P, int PC>
struct ret_jmp;
template <class P, int PC, class Cmd>
struct ret_jmp_impl
: ret_jmp<P, PC - 1> {};
template <class P, int PC>
struct ret_jmp_impl<P, PC, end>
: ret_jmp<P, ret_jmp<P, PC - 1>::ret - 2> {};
template <class P, int PC>
struct ret_jmp_impl<P, PC, rep>
{
static const int ret = PC + 1;
};
template <class P, int PC>
struct ret_jmp
: ret_jmp_impl<P, PC, typename at<P, PC>::ret> {};
template <class S, bool Done>
struct cmd_end
: state<PROG(S), DATA(S), OUT(S), ret_jmp<PROG(S), S::pc - 1>::ret, S::dp> {};
template <class S>
struct cmd_end<S, true>
: state<PROG(S), DATA(S), OUT(S), S::pc + 1, S::dp> {};
template <class S>
struct cmd<S, end>
: cmd_end<S, S::val == 0> {};
//--------------------------------------------------------------
// Gets the length of a typelist.
//--------------------------------------------------------------
template <class List>
struct len
{
static const int ret = len<typename List::tail>::ret + 1;
};
template <>
struct len< typelist<> >
{
static const int ret = 0;
};
//--------------------------------------------------------------
// Runs a program from the given state and produces the final state
//--------------------------------------------------------------
template <class S>
struct run_impl;
template <class S, bool Done>
struct run_next
: run_impl<cmd<S, typename at<PROG(S), S::pc>::ret>> {};
template <class S>
struct run_next<S, true>
: S {};
template <class S>
struct run_impl
: run_next<S, S::pc == len<PROG(S)>::ret> {};
template <class P>
struct run
: run_impl< state<P, data<0, 0, 0, 0, 0>, data<>, 0, 0> > {};
//--------------------------------------------------------------
// Prints the program's output
//--------------------------------------------------------------
template <class Out>
void print()
{
print<typename Out::tail>();
std::cout << (char)Out::head;
}
template <>
void print<data<>>() {}
int main()
{
// Hello, World! in Brainf*ck (from wikipedia):
/*
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set the next four cells to 70/100/30/10
> +++++ ++ add 7 to cell #1
> +++++ +++++ add 10 to cell #2
> +++ add 3 to cell #3
> + add 1 to cell #4
<<<< - decrement counter (cell #0)
]
> ++ . print 'H'
> + . print 'e'
+++++ ++ . print 'l'
. print 'l'
+++ . print 'o'
> ++ . print ' '
<< +++++ +++++ +++++ . print 'W'
> . print 'o'
+++ . print 'r'
----- - . print 'l'
----- --- . print 'd'
> + . print '!'
> . print '\n' */
// Template metaprogram translation
typedef typelist
<
inc,inc,inc,inc,inc, inc,inc,inc,inc,inc,
rep,
nxt, inc,inc,inc,inc,inc, inc,inc,
nxt, inc,inc,inc,inc,inc, inc,inc,inc,inc,inc,
nxt, inc,inc,inc,
nxt, inc,
prv,prv,prv,prv, dec,
end,
nxt, inc,inc, out,
nxt, inc, out,
inc,inc,inc,inc,inc, inc,inc, out,
out,
inc,inc,inc, out,
nxt, inc,inc, out,
prv,prv, inc,inc,inc,inc,inc, inc,inc,inc,inc,inc, inc,inc,inc,inc,inc, out,
nxt, out,
inc,inc,inc, out,
dec,dec,dec,dec,dec, dec, out,
dec,dec,dec,dec,dec, dec,dec,dec, out,
nxt, inc, out,
nxt, out
> program;
print< run<program>::out >();
std::cout << std::endl;
}
Anyone else got any interesting metaprograms?
I'm thinking of writing a more interesting metaprogramming language next. Brainf*ck is a bit tedious to use ;)












