开发者

Alternatives to C++ templates?

开发者 https://www.devze.com 2022-12-18 11:59 出处:网络
I think meta programming is very very cool. In particular, I love lisp macros. However, I think C++ template suck because:

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 c开发者_JAVA技巧ompiler -> *.cpp -> g++ -> executable ?

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.


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?


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++ (even C++17), Java, C#, COBOL, PHP and a number of other programming languages, 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 language you'd like to manipulate. And you don't have to wait for the language designers and implementers to implement, nor do you have to live with the limitations of what they can imagine or actually implemented, or pay the runtime space/time price of all that reflective data it takes to support it.

And program transformation is more powerful than C++ template metaprogramming, despite TM being Turing capable! The reason is that TM can generate arbitrary 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).


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....


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 :)


If C++0x is an option, then some template meta-programing problems can be reduced to a set of constexpr functions executed at compile-time. For instance, consider compile-time regex matcher using constexpr. constexpr functions are also faster than C++ template meta-programs.

If you are into functional programming several other options are also available.

C++ Template Metaprogramming with Embedded Haskell

Meta Towards a Functional-Style Interface for C++ Template Metaprograms

Papers by Abel Sinkovics

0

精彩评论

暂无评论...
验证码 换一张
取 消