Boost logo

Boost :

From: Daniel Frey (d.frey_at_[hidden])
Date: 2003-10-17 16:11:41

Hi Boosters,

during the last weeks I developed a framework to represent
constants. Due to my lack of time, I haven't had the time to work on
all the details and ideas that might be important, but Paul Bristow
kindly reminded me that something should be shown "Real Soon Now" :)
Also, I was trying to make this a CUJ article, but since they ignore
me for two months now, I'll no longer wait for them...

As I agree that it's better to have something than to have nothing at
all, I would like to ask for comments, help, discussion etc. with the code
I have. The code can be found in the files section, here's a link:


Current features include:

- Separation of framework and constants

  The framework to provide and handle constants is separated from the
  definition of constants itself. The definition is reduced to a
  straight forward and easy syntax. One framework can be used for
  different sets of constants, e.g. mathematical constants, physical
  constants, etc.

- No brackets for constants
  A constant is accessed as 'pi', not 'pi()'.

- Explicit type selection
  You can use static_cast to convert a constant to a given type. Nice
  for generic programming.

- Implicit type selection

  Combining a constant with a non-constant automatically converts the
  constant to the non-constant's type. Should IMHO match most people's
  expectations. Example: 'pi * 2.' selects the 'double'-version of
  'pi'. Also works for other uses like 'double d = pi;'.

- Composed constants

  You can define 'pi * pi' as a single constant. The user needn't
  remember a special naming convention for it like 'pi2', 'pi_squared'
  or 'squared_pi'. No run-time multiplication of loss of precision
  involved. One drawback: 'srqt( two )' is required instead of
  'sqrt( 2 )' as 2 is always of type integer, not constant<...>, so it
  cannot be detected as a constant.

- On demand extension for composed constants

  If you need special constants that are not predefined by the
  library, you can add them without touching the library itself. As
  this is an optimization, it's invisible from the outside and you can
  ignore it during development. Well, you do need to use an indirect
  include, though. (More on that later...)

- Lazy type selection

  const double d = 1.;
  const double d2 = sqrt( pi ) * d;

  In this example, sqrt( pi ) is either a composed constant or it's
  type is selected by 'd'. Works for complex expressions like

  const double d = sqrt( sqrt( pi + pi ) / pi );

- Few operators

  Unlike several other frameworks, no operators or function overloads
  are define pre-constant. Should help to keep the compiler in trim :)

- No required pessimisations

  The framework itself allows compilers to produce code which is as
  good as hand-written code. Of course, not all compilers make use of
  these opportunities. I tested the GCC and the Intel compiler, the
  latter can produce optimal code, the former has some problems,
  though. Last tested: GCC 3.3, maybe this has improved since, further
  testing is definitly needed. To be fair, I should also mention that
  Paul Bristow tried the run the code through the VC++, which
  failed. The code seems to be a bit challanging, but I haven't given
  up hope. If you can make it work for the VC++, please let me know :)

OK, so much for the advertising section. The code I placed in the
files section is a single source which contains everything needed and
doesn't require boost. I hope this is convenient for everybody. I
called it M1 for Milestone 1 as I think it will need more work before
a formal review can be approached. My personal roadmap is only a quick
hack and comments on it are appreciated - as are comments on the code
itself :)

M1: See if anyone's interested :)
    Get comments about big picture issues
M2: Support VC++ if possible
    More features as needed
M3: Stabilize the code, start boostification
    Add mathematical constants as separate part (Paul, would you mind
    or even like doing this? :)
    Add preliminary documentation
M4: Complete documentation, ask for formal review

Each milestone might have several versions. No time shedule is given
since this is only a hobby and my time is very limited, so I try not
to promise anything I can't keep. If you would like to speed things
up, just start helping me :o)

Some ideas I had which are not yet included in the code:

- Generic types

  Today, adding a new type means you have to provide all variables
  for the new type. As a default, I think it might make sense to
  provide a function which can either convert this type from another
  type if the precision and efficiency is sufficient (should actually
  be easy), or we could provide a special function which returns a
  string with the requested length which in turn can be used to
  initialized the new type's constant. See the code with the
  Roguewave-type as a example for a type where this would make
  sense. Algorithms to provide 'pi' with the required precision are
  usually available, although it's a lot of work :)

- Better syntax through a language extension

  This is probably unrealistic, but why can't I overload functions on
  integral constant expressions? sqrt(2) reads so much nicer than
  sqrt(two). The syntax for these overloads could look like this:

  template< int I > result_type sqrt( int I ) { /* I is an ICE here */ }
  template<> result_type sqrt( int 2 ) { /* Specialization for I=2 */ }
  result_type sqrt( int i ) { /* only used for non-ICEs */ }

  OK, this is probably not important for now, just an idea. It could
  even be used for other things but that should be discussed
  separately if there is interest.

Regards, Daniel

Boost list run by bdawes at, gregod at, cpdaniel at, john at