Boost logo

Boost :

From: Daniel Frey (daniel.frey_at_[hidden])
Date: 2003-01-07 10:13:24


Terje Slettebø wrote:
>
> BOOST_STATIC_CONST is defined in Boost.Config as:
>
> # ifdef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
> # define BOOST_STATIC_CONSTANT(type, assignment) enum { assignment }
> # else
> # define BOOST_STATIC_CONSTANT(type, assignment) static const type
> assignment
> # endif
>
> Thus, it prefers static const, if it's possible to initialise it in-class,
> on the given compiler, as allowed in the standard. However, "C++ Templates:

I prefer the enum-variant, but for other reasons which may not apply
here. With enums, the compilation might be much faster. I wrote a small
mandelbrot-metaprogram some time ago where the different in compilation
was a factor (!) of 3 on some compilers. It has to do with how many
(anonymous) types a compiler has to generate. To speed up compilation, I
put several values into a single enum. Instead of:

struct huhu {
  enum { foo = ... };
  enum { bar = ... };
};

I used:

struct huhu {
  enum {
    foo = ...,
    bar = ...,
  };
};

This is IMHO more readable when the list of values gets longer and the
compiler has less work to do. The question is, whether compilation time
is an issue for boost and if yes, how we can fix it ('static const int'
is comparable to the first version when talking about compilation
speed).

To play with the compile-time, here's the code I used (you might merge
some lines as my mailer will split them :) If you have trouble, drop me
a mail and I'll send it as an archive)

/*/ 2>/dev/null

#------------------------------------------------------------------------------
#
# ASCII-Mandelbrot - Template-Metaprogramming-Version
#
# Copyright (c) 2001 by Daniel Frey
#
# This is both a C++ source code and a bash script.
# Just start it and it will compile itself and
# (if compilation was successful) will start itself.
#
# Configure the program by adjusting the exported values below,
# but do not set CONFIG_DEPTH to a value > 26.
# Start playing with really small values like X=20, Y=9, DEPTH=10
#
# Also, try not to look like this smily when analysing this file: =8*/

#define export static const int

export CONFIG_SIZE_X=40;
export CONFIG_SIZE_Y=21;
export CONFIG_DEPTH=15;

#undef export
#include <iostream>

/*/ 2>/dev/null

time g++ -Wall -O2 -ftemplate-depth-$(( ( $CONFIG_SIZE_X + 1 ) *
$CONFIG_SIZE_Y + $CONFIG_DEPTH )) $0 -o $0.exe && time ./$0.exe

exit; */ using std::cout;

//-----------------------------------------------------------------------------
// Configuration:

// The shown section of the mandelbrot-fractal:
static const double MIN_X = -2.5, MAX_X = 1.5;
static const double MIN_Y = -1.5, MAX_Y = 1.5;

static const int NORM_LIMIT = 10000;

// Use this "mapping" to store floats in ints:
static const int SCALE = 1024;

//-----------------------------------------------------------------------------
// Mapped configuration:

static const int MAPPED_MIN_X = int( MIN_X * SCALE );
static const int MAPPED_MAX_X = int( MAX_X * SCALE );
static const int MAPPED_MIN_Y = int( MIN_Y * SCALE );
static const int MAPPED_MAX_Y = int( MAX_Y * SCALE );

static const int MAPPED_RANGE_X = MAPPED_MAX_X - MAPPED_MIN_X;
static const int MAPPED_RANGE_Y = MAPPED_MAX_Y - MAPPED_MIN_Y;

static const int MAPPED_SIZE_X = CONFIG_SIZE_X - 1;
static const int MAPPED_SIZE_Y = CONFIG_SIZE_Y - 1;

static const int MAPPED_ITERATIONS = CONFIG_DEPTH - 1;

static const int MAPPED_NORM_LIMIT = NORM_LIMIT * SCALE;

//-----------------------------------------------------------------------------
// The calculation:

template< int X, int Y, int I = 0 >
class Value
{
  enum {
    z_real = Value< X, Y, I - 1 >::real,
    z_imag = Value< X, Y, I - 1 >::imag,

    c_real = MAPPED_RANGE_X * X / MAPPED_SIZE_X + MAPPED_MIN_X,
    c_imag = MAPPED_RANGE_Y * Y / MAPPED_SIZE_Y + MAPPED_MIN_Y,
  };

public:
  enum {
    // z' = z^2 + c
    real = ( z_real * z_real - z_imag * z_imag ) / SCALE + c_real,
    imag = 2 * z_real * z_imag / SCALE + c_imag,

    RET = ( ( real * real + imag * imag > MAPPED_NORM_LIMIT ) ? I : (
Value< X, Y, I + 1 >::RET ) ),
  };
};

template< int X, int Y >
struct Value< X, Y, -1 >
{
  enum {
    real = 0,
    imag = 0,
  };
};

template< int X, int Y >
struct Value< X, Y, MAPPED_ITERATIONS >
{
  enum {
    RET = -1,
  };
};

//-----------------------------------------------------------------------------
// The loop:

template< int X = 0, int Y = 0 >
class Loop
{
  enum {
    value = Value< X, Y >::RET,
  };

public:
  static inline void f()
  {
    cout << ( ( value == -1 ) ? ' ' : char( 'a' + value ) );
    Loop< X + 1, Y >::f();
  }
};

template< int Y >
struct Loop< CONFIG_SIZE_X, Y >
{
  static inline void f()
  {
    cout << '\n';
    Loop< 0, Y + 1 >::f();
  }
};

template<>
struct Loop< 0, CONFIG_SIZE_Y >
{
  static inline void f() {}
};

//-----------------------------------------------------------------------------
// Main:

int main()
{
  Loop<>::f();
}

In the class Value, you might want to replace the enum-blocks by single
enums to see the difference.

Regards, Daniel

-- 
Daniel Frey
aixigo AG - financial training, research and technology
Schloß-Rahe-Straße 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey_at_[hidden], web: http://www.aixigo.de

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk