On Jul 20, 2008, at 9:21 AM, Zeljko Vrba wrote:
And the basic question remains unanswered for me: How does MPL (or
fusion for
that matter) help in making more maintainable code? More
maintainable as in:
- less lines of code
- code that is easier to understand
- code that is easier to inspect at runtime with a debugger
- code that can be modified by a C++ developer who does not know
every dark
corner of the template language
- code that is written faster (i.e. takes less time to get a
successful
compilation) and works correctly the first time it is written
How are fusion/MPL useful to an *application* programmer, not a
library
developer?
I'm not really into the whole MPL scene myself, but I'll give you
examples where I used it.
A while ago, Boost.Test added support for automatic unit tests. I
tried them out, and converted Boost.Rational to use them. The test
come in the form of a function you write with a special macro. A
similar macro was provided that made a function template instead, and
you supply a list of types to apply on that template for testing.
The list is in the form of a MPL list:
typedef boost::mpl::list
rational_testing_list;
And I could apply the same tests for different versions of
boost::rational<T>.
Recently, I redid the integer-selection class templates to use
Boost.Test. Before this (like in Boost 1.35) that test
(integer_test.cpp) used a LOT of macros that assumed 32-bit values.
I wanted something more maintainable by the compiler proper. (For
instance, someone extended a macro for 64-bit support, although I
never supported that for any other code.) I decided to go with
automatic test templates and lists. The base list was like:
typelist boost::mpl::vector unsigned_integer_list;
with some alterations:
1. Use "__int64" instead of "long long" on Windows systems
2. Exclude both if I'm not on a 64-bit system
3. Exclude types that are strong-typedefs of a "smaller" type
(so "unsigned char" is the only type guaranteed) done by the
preprocessor. I use MPL to synthesize the data I actually needed for
the tests from this list.
1. Create a list of corresponding signed types (help from
Boost.TypeTraits)
2. Create a list of bit lengths used for each integral type,
using a custom meta-function I made with std::numeric_limits. This
means that I didn't not hard-code the {8, 16, 32, 64} values and the
tests will work on platforms without a 64-bit type, or even on old
systems that don't use the 8/16/32 system (like 36-bit ints with 9-
bit char).
3. A list of all the median bit lengths between the values in
[2], so I can test lengths between the exact ones.
4. A combined list of [2] and [3]
5. [4] extended with a length beyond all valid bit lengths
In addition, I changed the implementation of the integer-selection
classes. Before they could give a compiler error if a given input
length was invalid. Now they're MPL-compatible and just lack a
member "type" if the input is invalid. (The old templates now call
these new ones and still cause a hard error.) Without this, tests
using [5] aren't possible. Said tests use SFINAE to make decisions.
(I think that MPL lists are limited to 20 elements total. So I made
list [3] to be selective. Otherwise, I could have carpet-bombed with
range_c or such.)
All of these lists are compile-time, but based on a list I couldn't
hard-code. It would have been harder without MPL manipulations.
--
Daryle Walker
Mac, Internet, and Video Game Junkie
darylew AT hotmail DOT com