views:

361

answers:

4

I think meta programming is very very cool. In particular, I love lisp macros.

However, I think C++ template suck because: 1) they slow down compile time (even with precompiled headers that end up being 50MB big if you include any of he STL stuff). 2) they give terrible compiler/syntax errors that are counintuitive 3) they weren't desinged for complicated meta programming in the first place (generating comipler errors for prime numbers / showing templates are turing complete was a big deal back in the day).

Having said all that, is there a decent alternative for C++ meta programming? something like

*.m -> meta compiler -> *.cpp -> g++ -> executable ?

Thanks!

EDIT:

I'm thikning along the lines of "custom code generations scripts." I'm just wondering if there's a really good set of them out there.

+1  A: 

If you're using C++ I think your only viable alternatives are either straight preprocessor macros, or custom code-generation.

The workflow you described would basically amount to some form of code-generation where you would pre-process your .m file into compilable c++ code. SWIG is a really good example of a project that does this.

Personally, I've had great success writing code-generators in Python but I think any scripting language would be just as good. One package that might be of use is cog from our very own Ned Batchelder :)

jkp
+4  A: 

I am not sure this is what should want, I have used code generators to produce C++ code. In particular, python cheetah. You basically embed straight python code inside your C++ code and run through cheetah preprocessor.it allows to do pretty complex computations much easier than using templates or C++ preprocessor, plus you get all python libraries and extensions. on the other hand it makes debugging harder if something goes wrong.if you are interested I could provide some examples and Emacs mode for editing cheetah C++ programs.

If you need something less powerful and want to stay within C++ C only, take a look at boost preprocessor, here. It takes a bit of time to get used to it, but could make life really easy when the repetitive code is involved

okay, I am pasting cheetah example, give me a few minutes:

#if defined (__INTEL_COMPILER)
#pragma vector aligned
#endif
        for(int a = 0; a < $N; ++a) {
            /// for functions in block
%for ii, (fi,fj) in enumerate(fb)
%set i = ii + ifb
/// can also use (ix,iy,iz)=fi[0:2], need to clean up when not lazy
%set ix = fi[0]
%set iy = fi[1]
%set iz = fi[2]
%set jx = fj[0]
%set jy = fj[1]
%set jz = fj[2]
            q$(i) += Ix(a,$(ix),$(jx))*Iy(a,$(iy),$(jy))*Iz(a,$(iz),$(jz));
%end for
            /// end for functions in block
        }

produces (after running cheetah ...)

#if defined (__INTEL_COMPILER)
#pragma vector aligned
#endif
        for(int a = 0; a < 6; ++a) {
            q0 += Ix(a,0,1)*Iy(a,0,0)*Iz(a,0,0);
            q1 += Ix(a,1,1)*Iy(a,0,0)*Iz(a,0,0);
            q2 += Ix(a,0,1)*Iy(a,1,0)*Iz(a,0,0);
            q3 += Ix(a,0,1)*Iy(a,0,0)*Iz(a,1,0);
            q4 += Ix(a,0,0)*Iy(a,0,1)*Iz(a,0,0);
            q5 += Ix(a,1,0)*Iy(a,0,1)*Iz(a,0,0);
            q6 += Ix(a,0,0)*Iy(a,1,1)*Iz(a,0,0);
            q7 += Ix(a,0,0)*Iy(a,0,1)*Iz(a,1,0);
            q8 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,0,1);
            q9 += Ix(a,1,0)*Iy(a,0,0)*Iz(a,0,1);
        }

which is a regular C++ code

lines starting with % are interpreted as python statements by cheetah preprocessor. /// are cheetah comments. Defaults use # as python statements, but I changed them to avoid collision with C preprocessor directives. %end must be used to terminate python blocks. Variables in C++ code which start with $ are replaced by python variables.

Do you want examples using boost preprocessor?

aaa
Please explain more.
anon
I have been doing something similar to this using Mako; I found this while looking for a more standard alternative.
Drew Wagner
A: 

Code generation is the best answer...

You should also look at how the Linux kernel does linked lists.

Linux Kernel Linked List Explained

The basic idea is that instead of having your type embedded in some struct (say with next and prev pointers, for a typical list implementation), you have the kernel list struct embedded in YOUR struct... Kind of mind bending, but check out the article... I never thought type safe generics were possible in C until I saw this....

dicroce
Except that, your example isn't type-safe, it's type-oblivious.
rlbond
ok, well, there is no casting involved anyway... :)
dicroce
@dicroce: the casting is hidden behind some macros. However for C where it's difficult or maybe impossible to do this kind of thing in a typesafe manner, this technique is quite useful. Windows has had similar macros (`CONTAINING_RECORD()`) for linked list manipulation as well. It's a nice technique given the limitations of C. And now I've learned a useful new term: "type oblivious".
Michael Burr
A: 

Most people insist on trying to metaprogram from inside their favorite language. C++ is held up as the quintessential example because of template metaprogramming. While it works, it is painful and clumsy. I find it telling the people figured out it was Turing-capable after Stroustrop added it to the language; I don't think even he expected it to turn out quite the way he did, although I doubt he'd complain about it now.

But most programming languages don't have metaprogramming facilities. (Or they may have weak or clumsy capabilities :)

A way around this is to do metaprogramming from outside the language, using program transformation tools. Such tools can parse source code, and carry out arbitrary transformations on it (that's what metaprogramming does anyway) and then spit the revised program.

If you have a general purpose program transformation system, that can parse arbitrary languages, you can then do metaprogramming on/with whatever language you like. See our DMS Software Reengineering Toolkit for such a tool, that have robust front ends for C, C++, Java, C#, COBOL, PHP and a number of other programming langauges, and has been used for metaprogramming on all of these.

This approach is useful because it provides a regular, methodological approach to providing metaprogramming methods for whatever langauge you'd like to manipulate.

And program transformation is more powerful than C++ template metaprogramming, despite TM being Turing capable! The reason is that TM can generate arbirary code from the templates, but cannot modify the non-template code. Program transformations can simulate TM if you insist, and so is at least as strong, but it can also carry out arbitrary changes to the non template code. Thus, strictly more powerful.

Like TM, using program transformations takes some effort to learn and apply. But being able to manipulate programs in arbitrary ways seems pretty useful.

(We've done architectural reengineering of very large C++ applications using DMS. TM simply can't do this).

Ira Baxter