Alex Rivera | Logout

What is metaprogramming?

Asked 2009-06-11T11:01:54.193
18

With reference to this question, could anybody please explain and post example code of metaprogramming? I googled the term up, but I found no examples to convince me that it can be of any practical use.

On the same note, is Qt's Meta Object System a form of metaprogramming?

Edit
Report

4 Answers

10

The concept comes entirely from the name Meta- means to abstract from the thing it is prefixed on.
In more 'conversational style' to do something with the thing rather than the thing itself.

In this regard metaprogramming is essentially writing code, which writes (or causes to be written) more code.

The C++ template system is meta programming since it doesn't simply do textual substitution (as the c preprocessor does) but has a (complex and inefficient) means of interacting with the code structure it parses to output code that is far more complex. In this regard the template preprocessing in C++ is Turing complete. This is not a requirement to say that something is metaprogramming but is almost certainly sufficient to be counted as such.

Code generation tools which are parametrizable may be considered metaprogramming if their template logic is sufficiently complex.

The closer a system gets to working with the abstract syntax tree that represents the language (as opposed to the textual form we represent it in) the more likely it is to be considered metaprogramming.

From looking at the QT MetaObjects code I would not (from a cursory inspection) call it meta programming in the sense usually reserved for things like the C++ template system or Lisp macros. It appears to simply be a form of code generation which injects some functionality into existing classes at the compile stage (it can be viewed as a precursor to the sort of Aspect Oriented Programming style currently in vogue or the prototype based object systems in languages like JavaScripts

As example of the sort of extreme lengths you can take this in C++ there is Boost MPL whose answered 2009-06-11T11:17:44.857

2

The following example is lifted from the excellent book C++ Templates - The complete guide.

#include <iostream>
using namespace std;

template <int N> struct Pow3 {
   enum { pow = 3 * Pow3<N-1>::pow };
}

template <> struct Pow3<0> {
   enum { pow = 1 };
}

int main() {
   cout << "3 to the 7 is " << Pow<7>::pow << "\n";
}

The point of this code is that the recursive calculation of the 7th power of 3 takes place at compile time rather than run time. It is thus extremely efficient in terms of runtime performance, at the expense of slower compilation.

Is this useful? In this example, probably not. But there are problems where performing calculations at compile time can be an advantage.

answered 2009-06-11T11:11:16.247
2

It's hard to say what C++ meta-programming is. More and more I feel it is much like introducing 'types' as variables, in the way functional programming has it. It renders declarative programming possible in C++.

It's way easier to show examples.

One of my favorites is a 'trick' (or pattern:) ) to flatte multiply nested switch/case blocks:

#include <iostream>
using namespace std;

enum CCountry { Belgium, Japan };
enum CEra     { ancient, medieval, future };

// nested switch
void historic( CCountry country, CEra era ) {
  switch( country ) {
        case( Belgium ):
          switch( era ) {
            case( ancient ): cout << "Ambiorix"; break;
            case( medieval ): cout << "Keizer Karel"; break;
          }
          break;
        case( Japan ):
          switch( era ) {
            case( future ): cout << "another Ruby?"; break;
            case( medieval ): cout << "Musashi Mijamoto"; break;
          }
          break;
  }
}


// the flattened, metaprogramming way
// define the conversion from 'runtime arguments' to compile-time arguments (if needed...)
// or use just as is.
template< CCountry country, CEra era > void thistoric();


template<> void thistoric<Belgium, ancient> () { cout << "Ambiorix"; }
template<> void thistoric<Belgium, medieval>() { cout << "Keizer Karel"; }
template<> void thistoric<Belgium, future  >() { cout << "Beer, lots of it"; }

template<> void thistoric<Japan, ancient> () { cout << "wikipedia"; }
template<> void thistoric<Japan, medieval>() { cout << "Musashi"; }
template<> void thistoric<Japan, future  >() { cout << "another Ruby?"; }


// optional: conversion from runtime to compile-time
//
template< CCountry country > struct SelectCountry {
  static void select( CEra era ) {
    switch (era) {
          case( medieva
answered 2009-06-11T12:05:31.840
0

This is a simple "value computation" along the lines of Factorial. However, it's one you are much more likely to actually use in your code.

The macro CT_NEXTPOWEROFTWO2(VAL) uses template metaprogramming to compute the next power of two greater than or equal to a value for values known at compile time.

template<long long int POW2VAL> class NextPow2Helper
{
    enum { c_ValueMinusOneBit     = (POW2VAL&(POW2VAL-1)) };
public:
    enum {
        c_TopBit                      = (c_ValueMinusOneBit) ?
            NextPow2Helper<c_ValueMinusOneBit>::c_TopBit : POW2VAL,
        c_Pow2ThatIsGreaterOrEqual    = (c_ValueMinusOneBit) ?
            (c_TopBit<<1) : c_TopBit
    };
};
template<> class NextPow2Helper<1>
{ public: enum { c_TopBit = 1, c_Pow2ThatIsGreaterOrEqual = 1 }; };
template<> class NextPow2Helper<0>
{ public: enum { c_TopBit = 0, c_Pow2ThatIsGreaterOrEqual = 0 }; };
// This only works for values known at Compile Time (CT)
#define CT_NEXTPOWEROFTWO2(VAL) NextPow2Helper<VAL>::c_Pow2ThatIsGreaterOrEqual
answered 2011-12-07T17:39:04.790

Your Answer