Boost logo

Boost :

From: Vesa Karvonen (vesa.karvonen_at_[hidden])
Date: 2001-05-24 12:11:21


From: "David Abrahams" <abrahams_at_[hidden]>
> From: "Vesa Karvonen" <vesa.karvonen_at_[hidden]>
[snip]
> If you reread it, you'll see that I made note of that problem in my
original
> message.

You are right. I must have forgotten that at some point. At any rate, both
of us seem to consider that as a disadvantage.

> It has implications (as does the current technique) for iterator_adaptor
> interoperability (see
>
http://www.boost.org/libs/utility/iterator_adaptors.htm#iterator_interaction
> s) that ought to be worked out. I think perhaps allowing any two
> iterator_adaptor<>s with the same Policies to interact at the interface
> level, and using a BOOST_STATIC_ASSERT() or some such to enforce that
> iterator_category and difference_type match would be fine.

My knowledge of the Boost iterator adaptors library is limited, but
comparing types in metaprograms is a well known technique (I think that some
Boost library already implements the notion). At any rate, if the issue can
be resolved using the current technique, then it can certainly be done with
the list approach.

However, my primary interest in presenting the list approach I have been
using, was to present an alternative. The list approach has the disadvantage
that the code computing the defaults, etc... can get much longer than in the
techniques used, for example, in the GP book. On the other hand, the order
problem vanishes.

Other alternatives that should be worth consideration:
- Reorder the template parameters by frequency of use. In fact, I assume
that it was already done, but sometimes even careful initial estimates can
be wrong.
- Use multiple generators each designed for a particular common usage
pattern. This way you can have multiple orders for the template arguments.
- Group the template parameters. Reducing the amount of individual template
parameters makes the template easier to use. If two or more template
parameters tend to be specified together, then group them into a simple
Parameter Object:

    template<class Param_1 = Default_1, class Param_2 = Default_2>
    struct Abstraction_Of_Params
    {
        typedef Param_1 Param_1;
        typedef Param_2 Param_2;
    };

In fact, this technique is useful even when the number of template arguments
is not large. I use it in my random sequence generator framework to clearly
separate horizontal and vertical parameters. The vertical parameters (in
that case parameters that affect the interface) are in the configuration
repository that is accessed from the parameterized base class. The
horizontal parameters (in that case parameters that affect the random number
generator, e.g. the multiplier and modulus for a multiplicative congruential
generator) are accessed from a class given as a template argument:

    template<long a, long m>
    struct Basic_Multiplicative_Congruential_Params
    {
      enum // Yes, I know the problems with enum and long!
      {
        a = a,
        m = m,
        q = m / a,
        r = m-a*q
      };
    };

    template<class Params, class Base>
    struct Multiplicative_Congruential
      : Base
    {
      typedef typename Base::Config
        Config;
      typedef typename Config::Seed_Type
        Seed_Type;
      // ...
    };

This has at least two useful consequences:
- It is now possible to provide multiple predefined parameters conveniently:

    template<long a = 16807, long m = 2147483647>
    struct Basic_Multiplicative_Congruential_Params;

    #define UMP_DEF(Name,a,m)\
     typedef Basic_Multiplicative_Congruential_Params<a,m>\
      Name;

    // WARNING: Unless you are a numerical analyst, you should not
    // use any other values than these.
    UMP_DEF(Alternate_Params_1, 48271, 2147483647)
    UMP_DEF(Alternate_Params_2, 69621, 2147483647)
    UMP_DEF(Alternate_Params_3, 40014, 2147483563)
    UMP_DEF(Alternate_Params_4, 40692, 2147483399)
    #undef UMP_DEF

Without the parameter object, you would need two distinct definitions for
each predefined parameter set.

- Because every generator, generator decorator and generator adaptor uses
exactly two template type parameters, it is possible to simplify metacode
that manipulates the generators.

> > Assuming that both "class Base" and "template<class T> class
> > std::iterator_traits" are accessible from the current scope, then in
> > standard C++ the expression "std::iterator_traits<Base>" can not cause
> > compilation errors.
>
> It's true. The problem is that the expression for the default argument is
> e.g. std::iterator_traits<Base>::value_type. If Base == int you have big
> trouble.

Again, my knowledge of the iterator adaptors library is limited, but issues
like this can be solved by using a few IF<> statements and metafunctions. If
a reasonably complex implementation allows a considerably simpler usage
patterns, then it can be worth it.


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